Magellan Linux

Diff of /tags/grubby-8_36/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 2250 by niro, Mon Oct 21 13:56:22 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        int rc = -1;
234    
235        if (i == -1) {
236     for (i = 0; configFiles[i] != NULL; i++) {
237        dbgPrintf("Checking \"%s\": ", configFiles[i]);
238        if ((rc = access(configFiles[i], R_OK))) {
239     if (errno == EACCES) {
240        printf("Unable to access bootloader configuration file "
241           "\"%s\": %m\n", configFiles[i]);
242        exit(1);
243     }
244     continue;
245        } else {
246     dbgPrintf("found\n");
247     return configFiles[i];
248        }
249     }
250        }
251    
252        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
253         * that isn't in grub1, and if it exists, return the config file path
254         * that they use. */
255        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
256     dbgPrintf("found\n");
257     return grub_cfg;
258        }
259    
260        dbgPrintf("not found\n");
261        return configFiles[i];
262    }
263    
264    int sizeOfSingleLine(struct singleLine * line) {
265      int count = 0;
266    
267      for (int i = 0; i < line->numElements; i++) {
268        int indentSize = 0;
269    
270        count = count + strlen(line->elements[i].item);
271    
272        indentSize = strlen(line->elements[i].indent);
273        if (indentSize > 0)
274          count = count + indentSize;
275        else
276          /* be extra safe and add room for whitespaces */
277          count = count + 1;
278      }
279    
280      /* room for trailing terminator */
281      count = count + 1;
282    
283      return count;
284    }
285    
286    static int isquote(char q)
287    {
288        if (q == '\'' || q == '\"')
289     return 1;
290        return 0;
291    }
292    
293    static int iskernel(enum lineType_e type) {
294        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
295    }
296    
297    static int isinitrd(enum lineType_e type) {
298        return (type == LT_INITRD || type == LT_INITRD_EFI);
299    }
300    
301    char *grub2ExtractTitle(struct singleLine * line) {
302        char * current;
303        char * current_indent;
304        int current_len;
305        int current_indent_len;
306        int i;
307    
308        /* bail out if line does not start with menuentry */
309        if (strcmp(line->elements[0].item, "menuentry"))
310          return NULL;
311    
312        i = 1;
313        current = line->elements[i].item;
314        current_len = strlen(current);
315    
316        /* if second word is quoted, strip the quotes and return single word */
317        if (isquote(*current) && isquote(current[current_len - 1])) {
318     char *tmp;
319    
320     tmp = strdup(current);
321     *(tmp + current_len - 1) = '\0';
322     return ++tmp;
323        }
324    
325        /* if no quotes, return second word verbatim */
326        if (!isquote(*current))
327     return current;
328    
329        /* second element start with a quote, so we have to find the element
330         * whose last character is also quote (assuming it's the closing one) */
331        int resultMaxSize;
332        char * result;
333        
334        resultMaxSize = sizeOfSingleLine(line);
335        result = malloc(resultMaxSize);
336        snprintf(result, resultMaxSize, "%s", ++current);
337        
338        i++;
339        for (; i < line->numElements; ++i) {
340     current = line->elements[i].item;
341     current_len = strlen(current);
342     current_indent = line->elements[i].indent;
343     current_indent_len = strlen(current_indent);
344    
345     strncat(result, current_indent, current_indent_len);
346     if (!isquote(current[current_len-1])) {
347        strncat(result, current, current_len);
348     } else {
349        strncat(result, current, current_len - 1);
350        break;
351     }
352        }
353        return result;
354    }
355    
356    struct configFileInfo grub2ConfigType = {
357        .findConfig = grub2FindConfig,
358        .keywords = grub2Keywords,
359        .defaultIsIndex = 1,
360        .defaultSupportSaved = 1,
361        .defaultIsVariable = 1,
362        .entryStart = LT_MENUENTRY,
363        .entryEnd = LT_ENTRY_END,
364        .titlePosition = 1,
365        .needsBootPrefix = 1,
366        .mbHyperFirst = 1,
367        .mbInitRdIsModule = 1,
368        .mbAllowExtraInitRds = 1,
369  };  };
370    
371  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 399  struct keywordTypes yabootKeywords[] = {
399      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
400      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
401      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
402      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
403      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
404      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
405      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 419  struct keywordTypes liloKeywords[] = {
419      { NULL,    0, 0 },      { NULL,    0, 0 },
420  };  };
421    
422    struct keywordTypes eliloKeywords[] = {
423        { "label",    LT_TITLE,    '=' },
424        { "root",    LT_ROOT,    '=' },
425        { "default",    LT_DEFAULT,    '=' },
426        { "image",    LT_KERNEL,    '=' },
427        { "initrd",    LT_INITRD,    '=' },
428        { "append",    LT_KERNELARGS,  '=' },
429        { "vmm",    LT_HYPER,       '=' },
430        { NULL,    0, 0 },
431    };
432    
433  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
434      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
435      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 451  struct keywordTypes ziplKeywords[] = {
451      { NULL,         0, 0 },      { NULL,         0, 0 },
452  };  };
453    
454    struct keywordTypes extlinuxKeywords[] = {
455        { "label",    LT_TITLE,    ' ' },
456        { "root",    LT_ROOT,    ' ' },
457        { "default",    LT_DEFAULT,    ' ' },
458        { "kernel",    LT_KERNEL,    ' ' },
459        { "initrd",    LT_INITRD,      ' ', ',' },
460        { "append",    LT_KERNELARGS,  ' ' },
461        { "prompt",     LT_UNKNOWN,     ' ' },
462        { NULL,    0, 0 },
463    };
464    int useextlinuxmenu;
465  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
466      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
467      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
468      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
469      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
470      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
471      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
472  };  };
473    
474  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
475      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
476      liloKeywords,    /* keywords */      .keywords = liloKeywords,
477      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
478      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
479      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
480  };  };
481    
482  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
483      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
484      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
485      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
486      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
487      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
488      1,    /* needsBootPrefix */      .maxTitleLength = 15,
489      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
490  };  };
491    
492  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
493      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
494      siloKeywords,    /* keywords */      .keywords = siloKeywords,
495      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
496      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
497      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
498      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
499  };  };
500    
501  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
502      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
503      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
504      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
505      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
506      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
507      0,    /* needsBootPrefix */  };
508      1,    /* argsInQuotes */  
509      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
510      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
511        .keywords = extlinuxKeywords,
512        .caseInsensitive = 1,
513        .entryStart = LT_TITLE,
514        .needsBootPrefix = 1,
515        .maxTitleLength = 255,
516        .mbAllowExtraInitRds = 1,
517  };  };
518    
519  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 528  struct grubConfig {
528      struct configFileInfo * cfi;      struct configFileInfo * cfi;
529  };  };
530    
531    blkid_cache blkid;
532    
533  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
534  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
535       const char * path, const char * prefix,       const char * path, const char * prefix,
536       int * index);       int * index);
 static char * strndup(char * from, int len);  
537  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
538  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
539    struct singleLine * lineDup(struct singleLine * line);
540  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
541  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
542       struct configFileInfo * cfi);       struct configFileInfo * cfi);
543  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
544         struct configFileInfo * cfi);         struct configFileInfo * cfi);
545  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
546    static void requote(struct singleLine *line, struct configFileInfo * cfi);
547  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
548      char * to;    const char * item, int insertHere,
549      struct configFileInfo * cfi);
550      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
551      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
552      to[len] = '\0';        struct configFileInfo * cfi);
553    static enum lineType_e getTypeByKeyword(char * keyword,
554      return to;   struct configFileInfo * cfi);
555  }  static struct singleLine * getLineByType(enum lineType_e type,
556     struct singleLine * line);
557    static int checkForExtLinux(struct grubConfig * config);
558    struct singleLine * addLineTmpl(struct singleEntry * entry,
559                                    struct singleLine * tmplLine,
560                                    struct singleLine * prevLine,
561                                    const char * val,
562     struct configFileInfo * cfi);
563    struct singleLine *  addLine(struct singleEntry * entry,
564                                 struct configFileInfo * cfi,
565                                 enum lineType_e type, char * defaultIndent,
566                                 const char * val);
567    
568  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
569  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 598  static char * sdupprintf(const char *for
598      return buf;      return buf;
599  }  }
600    
601    static enum lineType_e preferredLineType(enum lineType_e type,
602     struct configFileInfo *cfi) {
603        if (isEfi && cfi == &grub2ConfigType) {
604     switch (type) {
605     case LT_KERNEL:
606        return LT_KERNEL_EFI;
607     case LT_INITRD:
608        return LT_INITRD_EFI;
609     default:
610        return type;
611     }
612        }
613        return type;
614    }
615    
616    static struct keywordTypes * getKeywordByType(enum lineType_e type,
617          struct configFileInfo * cfi) {
618        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
619     if (kw->type == type)
620        return kw;
621        }
622        return NULL;
623    }
624    
625    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
626        struct keywordTypes *kt = getKeywordByType(type, cfi);
627        if (kt)
628     return kt->key;
629        return "unknown";
630    }
631    
632    static char * getpathbyspec(char *device) {
633        if (!blkid)
634            blkid_get_cache(&blkid, NULL);
635    
636        return blkid_get_devname(blkid, device, NULL);
637    }
638    
639    static char * getuuidbydev(char *device) {
640        if (!blkid)
641     blkid_get_cache(&blkid, NULL);
642    
643        return blkid_get_tag_value(blkid, "UUID", device);
644    }
645    
646    static enum lineType_e getTypeByKeyword(char * keyword,
647     struct configFileInfo * cfi) {
648        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
649     if (cfi->caseInsensitive) {
650        if (!strcasecmp(keyword, kw->key))
651                    return kw->type;
652     } else {
653        if (!strcmp(keyword, kw->key))
654            return kw->type;
655     }
656        }
657        return LT_UNKNOWN;
658    }
659    
660    static struct singleLine * getLineByType(enum lineType_e type,
661     struct singleLine * line) {
662        dbgPrintf("getLineByType(%d): ", type);
663        for (; line; line = line->next) {
664     dbgPrintf("%d:%s ", line->type,
665      line->numElements ? line->elements[0].item : "(empty)");
666     if (line->type & type) break;
667        }
668        dbgPrintf(line ? "\n" : " (failed)\n");
669        return line;
670    }
671    
672  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
673      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
674          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
675          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
676              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 682  static int isBracketedTitle(struct singl
682      return 0;      return 0;
683  }  }
684    
685  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
686                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
687      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
688   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;  
689  }  }
690    
691  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 736  static void lineInit(struct singleLine *
736      line->next = NULL;      line->next = NULL;
737  }  }
738    
739  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
740      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
741    
742        newLine->indent = strdup(line->indent);
743        newLine->next = NULL;
744        newLine->type = line->type;
745        newLine->numElements = line->numElements;
746        newLine->elements = malloc(sizeof(*newLine->elements) *
747           newLine->numElements);
748    
749        for (int i = 0; i < newLine->numElements; i++) {
750     newLine->elements[i].indent = strdup(line->elements[i].indent);
751     newLine->elements[i].item = strdup(line->elements[i].item);
752        }
753    
754        return newLine;
755    }
756    
757    static void lineFree(struct singleLine * line) {
758      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
759    
760      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
761   free(line->elements[i].item);   free(line->elements[i].item);
762   free(line->elements[i].indent);   free(line->elements[i].indent);
763      }      }
# Line 405  static void lineFree(struct singleLine * Line 768  static void lineFree(struct singleLine *
768    
769  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
770       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
771      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
772    
773      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
774     /* Need to handle this, because we strip the quotes from
775     * menuentry when read it. */
776     if (line->type == LT_MENUENTRY && i == 1) {
777        if(!isquote(*line->elements[i].item))
778     fprintf(out, "\'%s\'", line->elements[i].item);
779        else
780     fprintf(out, "%s", line->elements[i].item);
781        fprintf(out, "%s", line->elements[i].indent);
782    
783        continue;
784     }
785    
786   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
787      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
788    
789   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
790   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
791        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
792      }      }
793    
794      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 807  static int getNextLine(char ** bufPtr, s
807      char * chptr;      char * chptr;
808      int elementsAlloced = 0;      int elementsAlloced = 0;
809      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
810      int first = 1;      int first = 1;
     int i;  
811    
812      lineFree(line);      lineFree(line);
813    
# Line 489  static int getNextLine(char ** bufPtr, s Line 861  static int getNextLine(char ** bufPtr, s
861      if (!line->numElements)      if (!line->numElements)
862   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
863      else {      else {
864   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
865      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;  
               
866              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
867               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
868              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 876  static int getNextLine(char ** bufPtr, s
876      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
877   char * fullLine;   char * fullLine;
878   int len;   int len;
  int i;  
879    
880   len = strlen(line->indent);   len = strlen(line->indent);
881   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
882      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
883     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
884    
# Line 522  static int getNextLine(char ** bufPtr, s Line 887  static int getNextLine(char ** bufPtr, s
887   free(line->indent);   free(line->indent);
888   line->indent = fullLine;   line->indent = fullLine;
889    
890   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
891      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
892      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
893      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 897  static int getNextLine(char ** bufPtr, s
897   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
898   line->numElements = 0;   line->numElements = 0;
899      }      }
900     } else {
901     struct keywordTypes *kw;
902    
903     kw = getKeywordByType(line->type, cfi);
904    
905     /* space isn't the only separator, we need to split
906     * elements up more
907     */
908     if (!isspace(kw->separatorChar)) {
909        char indent[2] = "";
910        indent[0] = kw->separatorChar;
911        for (int i = 1; i < line->numElements; i++) {
912     char *p;
913     int numNewElements;
914    
915     numNewElements = 0;
916     p = line->elements[i].item;
917     while (*p != '\0') {
918     if (*p == kw->separatorChar)
919     numNewElements++;
920     p++;
921     }
922     if (line->numElements + numNewElements >= elementsAlloced) {
923     elementsAlloced += numNewElements + 5;
924     line->elements = realloc(line->elements,
925        sizeof(*line->elements) * elementsAlloced);
926     }
927    
928     for (int j = line->numElements; j > i; j--) {
929     line->elements[j + numNewElements] = line->elements[j];
930     }
931     line->numElements += numNewElements;
932    
933     p = line->elements[i].item;
934     while (*p != '\0') {
935    
936     while (*p != kw->separatorChar && *p != '\0') p++;
937     if (*p == '\0') {
938     break;
939     }
940    
941     line->elements[i + 1].indent = line->elements[i].indent;
942     line->elements[i].indent = strdup(indent);
943     *p++ = '\0';
944     i++;
945     line->elements[i].item = strdup(p);
946     }
947        }
948     }
949   }   }
950      }      }
951    
# Line 549  static struct grubConfig * readConfig(co Line 963  static struct grubConfig * readConfig(co
963      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
964      char * end;      char * end;
965      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
966      int i, len;      int len;
967      char * buf;      char * buf;
968    
969      if (!strcmp(inName, "-")) {      if (inName == NULL) {
970            printf("Could not find bootloader configuration\n");
971            exit(1);
972        } else if (!strcmp(inName, "-")) {
973   in = 0;   in = 0;
974      } else {      } else {
975   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1012  static struct grubConfig * readConfig(co
1012      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1013   }   }
1014    
1015   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1016      sawEntry = 1;      sawEntry = 1;
1017      if (!entry) {      if (!entry) {
1018   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1028  static struct grubConfig * readConfig(co
1028      entry->next = NULL;      entry->next = NULL;
1029   }   }
1030    
1031   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1032        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1033        dbgPrintf("%s", line->indent);
1034        for (int i = 0; i < line->numElements; i++)
1035     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1036        dbgPrintf("\n");
1037        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1038        if (kwType && line->numElements == 3 &&
1039        !strcmp(line->elements[1].item, kwType->key)) {
1040     dbgPrintf("Line sets default config\n");
1041     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1042     defaultLine = line;
1043        }
1044     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1045      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1046      defaultLine = line;      defaultLine = line;
1047    
1048            } else if (iskernel(line->type)) {
1049        /* if by some freak chance this is multiboot and the "module"
1050         * lines came earlier in the template, make sure to use LT_HYPER
1051         * instead of LT_KERNEL now
1052         */
1053        if (entry->multiboot)
1054     line->type = LT_HYPER;
1055    
1056          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1057        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1058         * instead, now that we know this is a multiboot entry.
1059         * This only applies to grub, but that's the only place we
1060         * should find LT_MBMODULE lines anyway.
1061         */
1062        for (struct singleLine *l = entry->lines; l; l = l->next) {
1063     if (l->type == LT_HYPER)
1064        break;
1065     else if (iskernel(l->type)) {
1066        l->type = LT_HYPER;
1067        break;
1068     }
1069        }
1070              entry->multiboot = 1;              entry->multiboot = 1;
1071    
1072     } else if (line->type == LT_HYPER) {
1073        entry->multiboot = 1;
1074    
1075   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1076      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1077      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1078    
1079   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1080      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1081      len = 0;      len = 0;
1082      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1083   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1084   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1085      }      }
1086      buf = malloc(len + 1);      buf = malloc(len + 1);
1087      *buf = '\0';      *buf = '\0';
1088    
1089      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1090   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1091   free(line->elements[i].item);   free(line->elements[i].item);
1092    
# Line 643  static struct grubConfig * readConfig(co Line 1100  static struct grubConfig * readConfig(co
1100      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1101      line->elements[1].item = buf;      line->elements[1].item = buf;
1102      line->numElements = 2;      line->numElements = 2;
1103     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1104        /* let --remove-kernel="TITLE=what" work */
1105        len = 0;
1106        char *extras;
1107        char *title;
1108    
1109        for (int i = 1; i < line->numElements; i++) {
1110     len += strlen(line->elements[i].item);
1111     len += strlen(line->elements[i].indent);
1112        }
1113        buf = malloc(len + 1);
1114        *buf = '\0';
1115    
1116        /* allocate mem for extra flags. */
1117        extras = malloc(len + 1);
1118        *extras = '\0';
1119    
1120        /* get title. */
1121        for (int i = 0; i < line->numElements; i++) {
1122     if (!strcmp(line->elements[i].item, "menuentry"))
1123        continue;
1124     if (isquote(*line->elements[i].item))
1125        title = line->elements[i].item + 1;
1126     else
1127        title = line->elements[i].item;
1128    
1129     len = strlen(title);
1130            if (isquote(title[len-1])) {
1131        strncat(buf, title,len-1);
1132        break;
1133     } else {
1134        strcat(buf, title);
1135        strcat(buf, line->elements[i].indent);
1136     }
1137        }
1138    
1139        /* get extras */
1140        int count = 0;
1141        for (int i = 0; i < line->numElements; i++) {
1142     if (count >= 2) {
1143        strcat(extras, line->elements[i].item);
1144        strcat(extras, line->elements[i].indent);
1145     }
1146    
1147     if (!strcmp(line->elements[i].item, "menuentry"))
1148        continue;
1149    
1150     /* count ' or ", there should be two in menuentry line. */
1151     if (isquote(*line->elements[i].item))
1152        count++;
1153    
1154     len = strlen(line->elements[i].item);
1155    
1156     if (isquote(line->elements[i].item[len -1]))
1157        count++;
1158    
1159     /* ok, we get the final ' or ", others are extras. */
1160                }
1161        line->elements[1].indent =
1162     line->elements[line->numElements - 2].indent;
1163        line->elements[1].item = buf;
1164        line->elements[2].indent =
1165     line->elements[line->numElements - 2].indent;
1166        line->elements[2].item = extras;
1167        line->numElements = 3;
1168   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1169      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1170         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 1173  static struct grubConfig * readConfig(co
1173      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1174   int last, len;   int last, len;
1175    
1176   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1177      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1178     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1179    
1180   last = line->numElements - 1;   last = line->numElements - 1;
1181   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1182   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1183      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1184      }      }
   
1185   }   }
1186    
1187   /* 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 1201  static struct grubConfig * readConfig(co
1201   movedLine = 1;   movedLine = 1;
1202   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1203   }   }
1204    
1205   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1206     which was moved, drop it. */     which was moved, drop it. */
1207   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 1217  static struct grubConfig * readConfig(co
1217   entry->lines = line;   entry->lines = line;
1218      else      else
1219   last->next = line;   last->next = line;
1220        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1221    
1222        /* we could have seen this outside of an entry... if so, we
1223         * ignore it like any other line we don't grok */
1224        if (line->type == LT_ENTRY_END && sawEntry)
1225     sawEntry = 0;
1226   } else {   } else {
1227      if (!cfg->theLines)      if (!cfg->theLines)
1228   cfg->theLines = line;   cfg->theLines = line;
1229      else {      else
1230   last->next = line;   last->next = line;
1231      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1232   }   }
1233    
1234   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1236  static struct grubConfig * readConfig(co
1236    
1237      free(incoming);      free(incoming);
1238    
1239        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1240      if (defaultLine) {      if (defaultLine) {
1241   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1242        cfi->defaultSupportSaved &&
1243        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1244        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1245     } else if (cfi->defaultIsVariable) {
1246        char *value = defaultLine->elements[2].item;
1247        while (*value && (*value == '"' || *value == '\'' ||
1248        *value == ' ' || *value == '\t'))
1249     value++;
1250        cfg->defaultImage = strtol(value, &end, 10);
1251        while (*end && (*end == '"' || *end == '\'' ||
1252        *end == ' ' || *end == '\t'))
1253     end++;
1254        if (*end) cfg->defaultImage = -1;
1255     } else if (cfi->defaultSupportSaved &&
1256   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1257      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1258   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1259      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1260      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1261   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1262      i = 0;      int i = 0;
1263      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1264   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1265      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1273  static struct grubConfig * readConfig(co
1273                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1274                  }                  }
1275   i++;   i++;
1276     entry = NULL;
1277      }      }
1278    
1279      if (entry) cfg->defaultImage = i;      if (entry){
1280            cfg->defaultImage = i;
1281        }else{
1282            cfg->defaultImage = -1;
1283        }
1284   }   }
1285        } else {
1286            cfg->defaultImage = 0;
1287      }      }
1288    
1289      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1299  static void writeDefault(FILE * out, cha
1299    
1300      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1301   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1302        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1303     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1304      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1305   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1306      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1307      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1308     cfg->defaultImage);
1309        } else {
1310     fprintf(out, "%sdefault%s%d\n", indent, separator,
1311     cfg->defaultImage);
1312        }
1313   } else {   } else {
1314      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1315    
# Line 769  static void writeDefault(FILE * out, cha Line 1326  static void writeDefault(FILE * out, cha
1326    
1327      if (!entry) return;      if (!entry) return;
1328    
1329      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1330    
1331      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1332   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1360  static int writeConfig(struct grubConfig
1360      int rc;      int rc;
1361    
1362      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1363         directory to / */         directory to the dir of the symlink */
1364      rc = chdir("/");      char *dir = strdupa(outName);
1365        rc = chdir(dirname(dir));
1366      do {      do {
1367   buf = alloca(len + 1);   buf = alloca(len + 1);
1368   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1369   if (rc == len) len += 256;   if (rc == len) len += 256;
1370      } while (rc == len);      } while (rc == len);
1371            
# Line 843  static int writeConfig(struct grubConfig Line 1400  static int writeConfig(struct grubConfig
1400      }      }
1401    
1402      line = cfg->theLines;      line = cfg->theLines;
1403        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1404      while (line) {      while (line) {
1405   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1406     line->numElements == 3 &&
1407     !strcmp(line->elements[1].item, defaultKw->key)) {
1408        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1409        needs &= ~MAIN_DEFAULT;
1410     } else if (line->type == LT_DEFAULT) {
1411      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1412      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1413   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1475  static int numEntries(struct grubConfig
1475      return i;      return i;
1476  }  }
1477    
1478  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1479    int skipRemoved, int flags) {  {
1480      struct singleLine * line;      int fd;
1481      char * fullName;      char buf[65536];
1482      int i;      char *devname;
1483      struct stat sb, sb2;      char *chptr;
1484      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1485    
1486      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1487      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1488                        _PATH_MOUNTED, strerror(errno));
1489      if (!line) return 0;          return NULL;
1490      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1491    
1492      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1493        if (rc <= 0) {
1494            fprintf(stderr, "grubby: failed to read %s: %s\n",
1495                    _PATH_MOUNTED, strerror(errno));
1496            close(fd);
1497            return NULL;
1498        }
1499        close(fd);
1500        buf[rc] = '\0';
1501        chptr = buf;
1502    
1503      fullName = alloca(strlen(bootPrefix) +      char *foundanswer = NULL;
       strlen(line->elements[1].item) + 1);  
     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;  
1504    
1505      for (i = 2; i < line->numElements; i++)      while (chptr && chptr != buf+rc) {
1506   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          devname = chptr;
     if (i < line->numElements) {  
  dev = line->elements[i].item + 5;  
     } else {  
  /* look for a lilo style LT_ROOT line */  
  line = entry->lines;  
  while (line && line->type != LT_ROOT) line = line->next;  
1507    
1508   if (line && line->numElements >= 2) {          /*
1509      dev = line->elements[1].item;           * The first column of a mtab entry is the device, but if the entry is a
1510   } else {           * special device it won't start with /, so move on to the next line.
1511              int type;           */
1512      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */          if (*devname != '/') {
1513      line = entry->lines;              chptr = strchr(chptr, '\n');
1514                if (chptr)
1515                    chptr++;
1516                continue;
1517            }
1518    
1519              type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);          /* Seek to the next space */
1520            chptr = strchr(chptr, ' ');
1521            if (!chptr) {
1522                fprintf(stderr, "grubby: error parsing %s: %s\n",
1523                        _PATH_MOUNTED, strerror(errno));
1524                return NULL;
1525            }
1526    
1527      while (line && line->type != type) line = line->next;          /*
1528             * The second column of a mtab entry is the mount point, we are looking
1529             * for '/' obviously.
1530             */
1531            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1532                /* remember the last / entry in mtab */
1533               foundanswer = devname;
1534            }
1535    
1536              /* failed to find one */          /* Next line */
1537              if (!line) return 0;          chptr = strchr(chptr, '\n');
1538            if (chptr)
1539                chptr++;
1540        }
1541    
1542      for (i = 1; i < line->numElements; i++)      /* Return the last / entry found */
1543          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;      if (foundanswer) {
1544      if (i < line->numElements)          chptr = strchr(foundanswer, ' ');
1545          dev = line->elements[i].item + 5;          *chptr = '\0';
1546      else {          return strdup(foundanswer);
1547   /* it failed too...  can't find root= */      }
1548          return 0;  
1549              }      return NULL;
1550    }
1551    
1552    void printEntry(struct singleEntry * entry, FILE *f) {
1553        int i;
1554        struct singleLine * line;
1555    
1556        for (line = entry->lines; line; line = line->next) {
1557     log_message(f, "DBG: %s", line->indent);
1558     for (i = 0; i < line->numElements; i++) {
1559        /* Need to handle this, because we strip the quotes from
1560         * menuentry when read it. */
1561        if (line->type == LT_MENUENTRY && i == 1) {
1562     if(!isquote(*line->elements[i].item))
1563        log_message(f, "\'%s\'", line->elements[i].item);
1564     else
1565        log_message(f, "%s", line->elements[i].item);
1566     log_message(f, "%s", line->elements[i].indent);
1567    
1568     continue;
1569        }
1570        
1571        log_message(f, "%s%s",
1572        line->elements[i].item, line->elements[i].indent);
1573   }   }
1574     log_message(f, "\n");
1575      }      }
1576    }
1577    
1578      if (!strncmp(dev, "LABEL=", 6)) {  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1579   dev += 6;  {
1580        static int once;
1581        va_list argp, argq;
1582    
1583        va_start(argp, fmt);
1584    
1585        va_copy(argq, argp);
1586        if (!once) {
1587     log_time(NULL);
1588     log_message(NULL, "command line: %s\n", saved_command_line);
1589        }
1590        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1591        log_vmessage(NULL, fmt, argq);
1592    
1593   /* check which device has this label */      printEntry(entry, NULL);
1594   dev = get_spec_by_volume_label(dev, &i, &i);      va_end(argq);
1595   if (!dev) return 0;  
1596        if (!debug) {
1597     once = 1;
1598         va_end(argp);
1599     return;
1600      }      }
1601    
1602      if (*dev == '/') {      if (okay) {
1603   if (stat(dev, &sb))   va_end(argp);
1604      return 0;   return;
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1605      }      }
     stat("/", &sb2);  
1606    
1607      if (sb.st_rdev != sb2.st_dev) return 0;      if (!once)
1608     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1609        once = 1;
1610        fprintf(stderr, "DBG: Image entry failed: ");
1611        vfprintf(stderr, fmt, argp);
1612        printEntry(entry, stderr);
1613        va_end(argp);
1614    }
1615    
1616    #define beginswith(s, c) ((s) && (s)[0] == (c))
1617    
1618    static int endswith(const char *s, char c)
1619    {
1620     int slen;
1621    
1622     if (!s || !s[0])
1623     return 0;
1624     slen = strlen(s) - 1;
1625    
1626     return s[slen] == c;
1627    }
1628    
1629    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1630      int skipRemoved, int flags) {
1631        struct singleLine * line;
1632        char * fullName;
1633        int i;
1634        char * dev;
1635        char * rootspec;
1636        char * rootdev;
1637    
1638        if (skipRemoved && entry->skip) {
1639     notSuitablePrintf(entry, 0, "marked to skip\n");
1640     return 0;
1641        }
1642    
1643        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1644        if (!line) {
1645     notSuitablePrintf(entry, 0, "no line found\n");
1646     return 0;
1647        }
1648        if (line->numElements < 2) {
1649     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1650        line->numElements);
1651     return 0;
1652        }
1653    
1654        if (flags & GRUBBY_BADIMAGE_OKAY) {
1655        notSuitablePrintf(entry, 1, "\n");
1656        return 1;
1657        }
1658    
1659        fullName = alloca(strlen(bootPrefix) +
1660          strlen(line->elements[1].item) + 1);
1661        rootspec = getRootSpecifier(line->elements[1].item);
1662        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1663        int hasslash = endswith(bootPrefix, '/') ||
1664         beginswith(line->elements[1].item + rootspec_offset, '/');
1665        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1666                line->elements[1].item + rootspec_offset);
1667        if (access(fullName, R_OK)) {
1668     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1669     return 0;
1670        }
1671        for (i = 2; i < line->numElements; i++)
1672     if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1673        if (i < line->numElements) {
1674     dev = line->elements[i].item + 5;
1675        } else {
1676     /* look for a lilo style LT_ROOT line */
1677     line = getLineByType(LT_ROOT, entry->lines);
1678    
1679     if (line && line->numElements >= 2) {
1680        dev = line->elements[1].item;
1681     } else {
1682        /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1683         * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1684         */
1685        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1686    
1687                /* failed to find one */
1688                if (!line) {
1689     notSuitablePrintf(entry, 0, "no line found\n");
1690     return 0;
1691                }
1692    
1693        for (i = 1; i < line->numElements; i++)
1694            if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1695        if (i < line->numElements)
1696            dev = line->elements[i].item + 5;
1697        else {
1698     notSuitablePrintf(entry, 0, "no root= entry found\n");
1699     /* it failed too...  can't find root= */
1700            return 0;
1701                }
1702     }
1703        }
1704    
1705        dev = getpathbyspec(dev);
1706        if (!getpathbyspec(dev)) {
1707            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1708            return 0;
1709        } else
1710     dev = getpathbyspec(dev);
1711    
1712        rootdev = findDiskForRoot();
1713        if (!rootdev) {
1714            notSuitablePrintf(entry, 0, "can't find root device\n");
1715     return 0;
1716        }
1717    
1718        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1719            notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1720     getuuidbydev(rootdev), getuuidbydev(dev));
1721            free(rootdev);
1722            return 0;
1723        }
1724    
1725        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1726            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1727     getuuidbydev(rootdev), getuuidbydev(dev));
1728     free(rootdev);
1729            return 0;
1730        }
1731    
1732        free(rootdev);
1733        notSuitablePrintf(entry, 1, "\n");
1734    
1735      return 1;      return 1;
1736  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1774  struct singleEntry * findEntryByPath(str
1774   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1775   if (!entry) return NULL;   if (!entry) return NULL;
1776    
1777   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1778   if (!line) return NULL;   if (!line) return NULL;
1779    
1780   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1812  struct singleEntry * findEntryByPath(str
1812    
1813   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1814      prefix = "";      prefix = "";
1815      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1816      kernel += 6;      kernel += 6;
1817   }   }
1818    
1819   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1820      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1821    
1822        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1823    
1824      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1825                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1826          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
1827                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1828                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1829                      break;   else if (checkType & LT_KERNEL)
1830              }      ct = checkType | LT_KERNEL_EFI;
1831                 line = getLineByType(ct, line);
1832              /* have to check multiboot lines too */   if (!line)
1833              if (entry->multiboot) {      break;  /* not found in this entry */
1834                  while (line && line->type != LT_MBMODULE) line = line->next;  
1835                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
1836                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
1837                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
1838                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
1839                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
1840                          break;   kernel + strlen(prefix)))
1841                  }   break;
1842              }   }
1843     if(line->type == LT_MENUENTRY &&
1844     !strcmp(line->elements[1].item, kernel))
1845        break;
1846        }
1847    
1848      i++;      /* make sure this entry has a kernel identifier; this skips
1849         * non-Linux boot entries (could find netbsd etc, though, which is
1850         * unfortunate)
1851         */
1852        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1853     break; /* found 'im! */
1854   }   }
1855    
1856   if (index) *index = i;   if (index) *index = i;
1857      }      }
1858    
     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);  
     }  
   
1859      return entry;      return entry;
1860  }  }
1861    
# Line 1200  void markRemovedImage(struct grubConfig Line 1934  void markRemovedImage(struct grubConfig
1934        const char * prefix) {        const char * prefix) {
1935      struct singleEntry * entry;      struct singleEntry * entry;
1936    
1937      if (!image) return;      if (!image)
1938     return;
1939    
1940        /* check and see if we're removing the default image */
1941        if (isdigit(*image)) {
1942     entry = findEntryByPath(cfg, image, prefix, NULL);
1943     if(entry)
1944        entry->skip = 1;
1945     return;
1946        }
1947    
1948      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1949   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1951  void markRemovedImage(struct grubConfig
1951    
1952  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1953       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1954       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1955      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1956      int i, j;      int i, j;
1957    
1958      if (newIsDefault) {      if (newIsDefault) {
1959   config->defaultImage = 0;   config->defaultImage = 0;
1960   return;   return;
1961        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1962     if (findEntryByIndex(config, index))
1963        config->defaultImage = index;
1964     else
1965        config->defaultImage = -1;
1966     return;
1967      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1968   i = 0;   i = 0;
1969   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1976  void setDefaultImage(struct grubConfig *
1976    
1977      /* 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
1978         changes */         changes */
1979      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1980     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1981        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1982        return;        return;
1983    
# Line 1286  void displayEntry(struct singleEntry * e Line 2036  void displayEntry(struct singleEntry * e
2036      char * root = NULL;      char * root = NULL;
2037      int i;      int i;
2038    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2039      printf("index=%d\n", index);      printf("index=%d\n", index);
2040    
2041      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
2042        if (!line) {
2043            printf("non linux entry\n");
2044            return;
2045        }
2046    
2047        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2048     printf("kernel=%s\n", line->elements[1].item);
2049        else
2050     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2051    
2052      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2053   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2064  void displayEntry(struct singleEntry * e
2064   }   }
2065   printf("\"\n");   printf("\"\n");
2066      } else {      } else {
2067   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2068   if (line) {   if (line) {
2069      char * s;      char * s;
2070    
# Line 1334  void displayEntry(struct singleEntry * e Line 2088  void displayEntry(struct singleEntry * e
2088      }      }
2089    
2090      if (!root) {      if (!root) {
2091   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2092   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2093      root=line->elements[1].item;      root=line->elements[1].item;
2094      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2103  void displayEntry(struct singleEntry * e
2103   printf("root=%s\n", s);   printf("root=%s\n", s);
2104      }      }
2105    
2106      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2107    
2108      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2109   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2110        printf("initrd=");
2111     else
2112        printf("initrd=%s", prefix);
2113    
2114   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2115      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2116   printf("\n");   printf("\n");
2117      }      }
2118    
2119        line = getLineByType(LT_TITLE, entry->lines);
2120        if (line) {
2121     printf("title=%s\n", line->elements[1].item);
2122        } else {
2123     char * title;
2124     line = getLineByType(LT_MENUENTRY, entry->lines);
2125     title = grub2ExtractTitle(line);
2126     if (title)
2127        printf("title=%s\n", title);
2128        }
2129    }
2130    
2131    int isSuseSystem(void) {
2132        const char * path;
2133        const static char default_path[] = "/etc/SuSE-release";
2134    
2135        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2136     path = default_path;
2137    
2138        if (!access(path, R_OK))
2139     return 1;
2140        return 0;
2141    }
2142    
2143    int isSuseGrubConf(const char * path) {
2144        FILE * grubConf;
2145        char * line = NULL;
2146        size_t len = 0, res = 0;
2147    
2148        grubConf = fopen(path, "r");
2149        if (!grubConf) {
2150            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2151     return 0;
2152        }
2153    
2154        while ((res = getline(&line, &len, grubConf)) != -1) {
2155     if (!strncmp(line, "setup", 5)) {
2156        fclose(grubConf);
2157        free(line);
2158        return 1;
2159     }
2160        }
2161    
2162        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2163          path);
2164    
2165        fclose(grubConf);
2166        free(line);
2167        return 0;
2168    }
2169    
2170    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2171        FILE * grubConf;
2172        char * line = NULL;
2173        size_t res = 0, len = 0;
2174    
2175        if (!path) return 1;
2176        if (!lbaPtr) return 1;
2177    
2178        grubConf = fopen(path, "r");
2179        if (!grubConf) return 1;
2180    
2181        while ((res = getline(&line, &len, grubConf)) != -1) {
2182     if (line[res - 1] == '\n')
2183        line[res - 1] = '\0';
2184     else if (len > res)
2185        line[res] = '\0';
2186     else {
2187        line = realloc(line, res + 1);
2188        line[res] = '\0';
2189     }
2190    
2191     if (!strncmp(line, "setup", 5)) {
2192        if (strstr(line, "--force-lba")) {
2193            *lbaPtr = 1;
2194        } else {
2195            *lbaPtr = 0;
2196        }
2197        dbgPrintf("lba: %i\n", *lbaPtr);
2198        break;
2199     }
2200        }
2201    
2202        free(line);
2203        fclose(grubConf);
2204        return 0;
2205    }
2206    
2207    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2208        FILE * grubConf;
2209        char * line = NULL;
2210        size_t res = 0, len = 0;
2211        char * lastParamPtr = NULL;
2212        char * secLastParamPtr = NULL;
2213        char installDeviceNumber = '\0';
2214        char * bounds = NULL;
2215    
2216        if (!path) return 1;
2217        if (!devicePtr) return 1;
2218    
2219        grubConf = fopen(path, "r");
2220        if (!grubConf) return 1;
2221    
2222        while ((res = getline(&line, &len, grubConf)) != -1) {
2223     if (strncmp(line, "setup", 5))
2224        continue;
2225    
2226     if (line[res - 1] == '\n')
2227        line[res - 1] = '\0';
2228     else if (len > res)
2229        line[res] = '\0';
2230     else {
2231        line = realloc(line, res + 1);
2232        line[res] = '\0';
2233     }
2234    
2235     lastParamPtr = bounds = line + res;
2236    
2237     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2238     while (!isspace(*lastParamPtr))
2239        lastParamPtr--;
2240     lastParamPtr++;
2241    
2242     secLastParamPtr = lastParamPtr - 2;
2243     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2244    
2245     if (lastParamPtr + 3 > bounds) {
2246        dbgPrintf("lastParamPtr going over boundary");
2247        fclose(grubConf);
2248        free(line);
2249        return 1;
2250     }
2251     if (!strncmp(lastParamPtr, "(hd", 3))
2252        lastParamPtr += 3;
2253     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2254    
2255     /*
2256     * Second last parameter will decide wether last parameter is
2257     * an IMAGE_DEVICE or INSTALL_DEVICE
2258     */
2259     while (!isspace(*secLastParamPtr))
2260        secLastParamPtr--;
2261     secLastParamPtr++;
2262    
2263     if (secLastParamPtr + 3 > bounds) {
2264        dbgPrintf("secLastParamPtr going over boundary");
2265        fclose(grubConf);
2266        free(line);
2267        return 1;
2268     }
2269     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2270     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2271        secLastParamPtr += 3;
2272        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2273        installDeviceNumber = *secLastParamPtr;
2274     } else {
2275        installDeviceNumber = *lastParamPtr;
2276     }
2277    
2278     *devicePtr = malloc(6);
2279     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2280     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2281     fclose(grubConf);
2282     free(line);
2283     return 0;
2284        }
2285    
2286        free(line);
2287        fclose(grubConf);
2288        return 1;
2289    }
2290    
2291    int grubGetBootFromDeviceMap(const char * device,
2292         char ** bootPtr) {
2293        FILE * deviceMap;
2294        char * line = NULL;
2295        size_t res = 0, len = 0;
2296        char * devicePtr;
2297        char * bounds = NULL;
2298        const char * path;
2299        const static char default_path[] = "/boot/grub/device.map";
2300    
2301        if (!device) return 1;
2302        if (!bootPtr) return 1;
2303    
2304        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2305     path = default_path;
2306    
2307        dbgPrintf("opening grub device.map file from: %s\n", path);
2308        deviceMap = fopen(path, "r");
2309        if (!deviceMap)
2310     return 1;
2311    
2312        while ((res = getline(&line, &len, deviceMap)) != -1) {
2313            if (!strncmp(line, "#", 1))
2314        continue;
2315    
2316     if (line[res - 1] == '\n')
2317        line[res - 1] = '\0';
2318     else if (len > res)
2319        line[res] = '\0';
2320     else {
2321        line = realloc(line, res + 1);
2322        line[res] = '\0';
2323     }
2324    
2325     devicePtr = line;
2326     bounds = line + res;
2327    
2328     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2329        devicePtr++;
2330     dbgPrintf("device: %s\n", devicePtr);
2331    
2332     if (!strncmp(devicePtr, device, strlen(device))) {
2333        devicePtr += strlen(device);
2334        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2335            devicePtr++;
2336    
2337        *bootPtr = strdup(devicePtr);
2338        break;
2339     }
2340        }
2341    
2342        free(line);
2343        fclose(deviceMap);
2344        return 0;
2345    }
2346    
2347    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2348        char * grubDevice;
2349    
2350        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2351     dbgPrintf("error looking for grub installation device\n");
2352        else
2353     dbgPrintf("grubby installation device: %s\n", grubDevice);
2354    
2355        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2356     dbgPrintf("error looking for grub boot device\n");
2357        else
2358     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2359    
2360        free(grubDevice);
2361        return 0;
2362    }
2363    
2364    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2365        /*
2366         * This SuSE grub configuration file at this location is not your average
2367         * grub configuration file, but instead the grub commands used to setup
2368         * grub on that system.
2369         */
2370        const char * path;
2371        const static char default_path[] = "/etc/grub.conf";
2372    
2373        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2374     path = default_path;
2375    
2376        if (!isSuseGrubConf(path)) return 1;
2377    
2378        if (lbaPtr) {
2379            *lbaPtr = 0;
2380            if (suseGrubConfGetLba(path, lbaPtr))
2381                return 1;
2382        }
2383    
2384        if (bootPtr) {
2385            *bootPtr = NULL;
2386            suseGrubConfGetBoot(path, bootPtr);
2387        }
2388    
2389        return 0;
2390  }  }
2391    
2392  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2396  int parseSysconfigGrub(int * lbaPtr, cha
2396      char * start;      char * start;
2397      char * param;      char * param;
2398    
2399      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2400      if (!in) return 1;      if (!in) return 1;
2401    
2402      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2437  int parseSysconfigGrub(int * lbaPtr, cha
2437  }  }
2438    
2439  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2440      char * boot;      char * boot = NULL;
2441      int lba;      int lba;
2442    
2443      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2444   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2445   if (boot) printf("boot=%s\n", boot);      free(boot);
2446        return;
2447     }
2448        } else {
2449            if (parseSysconfigGrub(&lba, &boot)) {
2450        free(boot);
2451        return;
2452     }
2453        }
2454    
2455        if (lba) printf("lba\n");
2456        if (boot) {
2457     printf("boot=%s\n", boot);
2458     free(boot);
2459      }      }
2460  }  }
2461    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2471  int displayInfo(struct grubConfig * conf
2471   return 1;   return 1;
2472      }      }
2473    
2474      /* 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
2475         be a better way */         be a better way */
2476      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2477   dumpSysconfigGrub();   dumpSysconfigGrub();
2478      } else {      } else {
2479   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2480   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2481      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2482   }   }
2483    
2484   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2485   if (line) printf("lba\n");   if (line) printf("lba\n");
2486      }      }
2487    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2496  int displayInfo(struct grubConfig * conf
2496      return 0;      return 0;
2497  }  }
2498    
2499    struct singleLine * addLineTmpl(struct singleEntry * entry,
2500     struct singleLine * tmplLine,
2501     struct singleLine * prevLine,
2502     const char * val,
2503     struct configFileInfo * cfi)
2504    {
2505        struct singleLine * newLine = lineDup(tmplLine);
2506    
2507        if (isEfi && cfi == &grub2ConfigType) {
2508     enum lineType_e old = newLine->type;
2509     newLine->type = preferredLineType(newLine->type, cfi);
2510     if (old != newLine->type)
2511        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2512        }
2513    
2514        if (val) {
2515     /* override the inherited value with our own.
2516     * This is a little weak because it only applies to elements[1]
2517     */
2518     if (newLine->numElements > 1)
2519        removeElement(newLine, 1);
2520     insertElement(newLine, val, 1, cfi);
2521    
2522     /* but try to keep the rootspec from the template... sigh */
2523     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2524        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2525        if (rootspec != NULL) {
2526     free(newLine->elements[1].item);
2527     newLine->elements[1].item =
2528        sdupprintf("%s%s", rootspec, val);
2529        }
2530     }
2531        }
2532    
2533        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2534          newLine->elements[0].item : "");
2535    
2536        if (!entry->lines) {
2537     /* first one on the list */
2538     entry->lines = newLine;
2539        } else if (prevLine) {
2540     /* add after prevLine */
2541     newLine->next = prevLine->next;
2542     prevLine->next = newLine;
2543        }
2544    
2545        return newLine;
2546    }
2547    
2548  /* val may be NULL */  /* val may be NULL */
2549  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2550       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2551       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2552       char * val) {       const char * val) {
2553      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2554      int i;      struct keywordTypes * kw;
2555        struct singleLine tmpl;
2556    
2557      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2558   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2559      if (type != LT_TITLE || !cfi->titleBracketed)       */
2560          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2561     /* we're doing a bracketed title (zipl) */
2562     tmpl.type = type;
2563     tmpl.numElements = 1;
2564     tmpl.elements = alloca(sizeof(*tmpl.elements));
2565     tmpl.elements[0].item = alloca(strlen(val)+3);
2566     sprintf(tmpl.elements[0].item, "[%s]", val);
2567     tmpl.elements[0].indent = "";
2568     val = NULL;
2569        } else if (type == LT_MENUENTRY) {
2570     char *lineend = "--class gnu-linux --class gnu --class os {";
2571     if (!val) {
2572        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2573        abort();
2574     }
2575     kw = getKeywordByType(type, cfi);
2576     if (!kw) {
2577        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2578        abort();
2579     }
2580     tmpl.indent = "";
2581     tmpl.type = type;
2582     tmpl.numElements = 3;
2583     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2584     tmpl.elements[0].item = kw->key;
2585     tmpl.elements[0].indent = alloca(2);
2586     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2587     tmpl.elements[1].item = (char *)val;
2588     tmpl.elements[1].indent = alloca(2);
2589     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2590     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2591     strcpy(tmpl.elements[2].item, lineend);
2592     tmpl.elements[2].indent = "";
2593        } else {
2594     kw = getKeywordByType(type, cfi);
2595     if (!kw) {
2596        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2597        abort();
2598     }
2599     tmpl.type = type;
2600     tmpl.numElements = val ? 2 : 1;
2601     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2602     tmpl.elements[0].item = kw->key;
2603     tmpl.elements[0].indent = alloca(2);
2604     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2605     if (val) {
2606        tmpl.elements[1].item = (char *)val;
2607        tmpl.elements[1].indent = "";
2608     }
2609        }
2610    
2611      /* 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
2612         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2613         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
2614         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2615         differently from the rest) */         differently from the rest) */
2616      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2617   line = entry->lines;   if (line->numElements) prev = line;
2618   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2619   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;  
2620      }      }
2621    
2622      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2623          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2624          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2625          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2626          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2627          line->elements[0].indent = malloc(2);   else
2628          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2629          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2630             if (menuEntry)
2631          if (val) {      tmpl.indent = "\t";
2632              line->elements[1].item = val;   else if (prev == entry->lines)
2633              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2634          }   else
2635      } 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("");  
2636      }      }
2637    
2638      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2639  }  }
2640    
2641  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2660  void removeLine(struct singleEntry * ent
2660      free(line);      free(line);
2661  }  }
2662    
2663    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2664    {
2665        struct singleLine newLine = {
2666     .indent = tmplLine->indent,
2667     .type = tmplLine->type,
2668     .next = tmplLine->next,
2669        };
2670        int firstQuotedItem = -1;
2671        int quoteLen = 0;
2672        int j;
2673        int element = 0;
2674        char *c;
2675    
2676        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2677        strcpy(c, tmplLine->elements[0].item);
2678        insertElement(&newLine, c, element++, cfi);
2679        free(c);
2680        c = NULL;
2681    
2682        for (j = 1; j < tmplLine->numElements; j++) {
2683     if (firstQuotedItem == -1) {
2684        quoteLen += strlen(tmplLine->elements[j].item);
2685        
2686        if (isquote(tmplLine->elements[j].item[0])) {
2687     firstQuotedItem = j;
2688            quoteLen += strlen(tmplLine->elements[j].indent);
2689        } else {
2690     c = malloc(quoteLen + 1);
2691     strcpy(c, tmplLine->elements[j].item);
2692     insertElement(&newLine, c, element++, cfi);
2693     free(c);
2694     quoteLen = 0;
2695        }
2696     } else {
2697        int itemlen = strlen(tmplLine->elements[j].item);
2698        quoteLen += itemlen;
2699        quoteLen += strlen(tmplLine->elements[j].indent);
2700        
2701        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2702     c = malloc(quoteLen + 1);
2703     c[0] = '\0';
2704     for (int i = firstQuotedItem; i < j+1; i++) {
2705        strcat(c, tmplLine->elements[i].item);
2706        strcat(c, tmplLine->elements[i].indent);
2707     }
2708     insertElement(&newLine, c, element++, cfi);
2709     free(c);
2710    
2711     firstQuotedItem = -1;
2712     quoteLen = 0;
2713        }
2714     }
2715        }
2716        while (tmplLine->numElements)
2717     removeElement(tmplLine, 0);
2718        if (tmplLine->elements)
2719     free(tmplLine->elements);
2720    
2721        tmplLine->numElements = newLine.numElements;
2722        tmplLine->elements = newLine.elements;
2723    }
2724    
2725    static void insertElement(struct singleLine * line,
2726      const char * item, int insertHere,
2727      struct configFileInfo * cfi)
2728    {
2729        struct keywordTypes * kw;
2730        char indent[2] = "";
2731    
2732        /* sanity check */
2733        if (insertHere > line->numElements) {
2734     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2735      insertHere, line->numElements);
2736     insertHere = line->numElements;
2737        }
2738    
2739        line->elements = realloc(line->elements, (line->numElements + 1) *
2740         sizeof(*line->elements));
2741        memmove(&line->elements[insertHere+1],
2742        &line->elements[insertHere],
2743        (line->numElements - insertHere) *
2744        sizeof(*line->elements));
2745        line->elements[insertHere].item = strdup(item);
2746    
2747        kw = getKeywordByType(line->type, cfi);
2748    
2749        if (line->numElements == 0) {
2750     indent[0] = '\0';
2751        } else if (insertHere == 0) {
2752     indent[0] = kw->nextChar;
2753        } else if (kw->separatorChar != '\0') {
2754     indent[0] = kw->separatorChar;
2755        } else {
2756     indent[0] = ' ';
2757        }
2758    
2759        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2760     /* move the end-of-line forward */
2761     line->elements[insertHere].indent =
2762        line->elements[insertHere-1].indent;
2763     line->elements[insertHere-1].indent = strdup(indent);
2764        } else {
2765     line->elements[insertHere].indent = strdup(indent);
2766        }
2767    
2768        line->numElements++;
2769    
2770        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2771          line->elements[0].item,
2772          line->elements[insertHere].item,
2773          line->elements[insertHere].indent,
2774          insertHere);
2775    }
2776    
2777    static void removeElement(struct singleLine * line, int removeHere) {
2778        int i;
2779    
2780        /* sanity check */
2781        if (removeHere >= line->numElements) return;
2782    
2783        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2784          removeHere, line->elements[removeHere].item);
2785    
2786        free(line->elements[removeHere].item);
2787    
2788        if (removeHere > 1) {
2789     /* previous argument gets this argument's post-indentation */
2790     free(line->elements[removeHere-1].indent);
2791     line->elements[removeHere-1].indent =
2792        line->elements[removeHere].indent;
2793        } else {
2794     free(line->elements[removeHere].indent);
2795        }
2796    
2797        /* now collapse the array, but don't bother to realloc smaller */
2798        for (i = removeHere; i < line->numElements - 1; i++)
2799     line->elements[i] = line->elements[i + 1];
2800    
2801        line->numElements--;
2802    }
2803    
2804  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2805      char * first, * second;      char * first, * second;
2806      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2823  int updateActualImage(struct grubConfig
2823      struct singleEntry * entry;      struct singleEntry * entry;
2824      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2825      int index = 0;      int index = 0;
2826      int i, j, k;      int i, k;
2827      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2828      const char ** arg;      const char ** arg;
2829      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2830      int firstElement;      int firstElement;
2831      int *usedElements, *usedArgs;      int *usedElements;
2832        int doreplace;
2833    
2834      if (!image) return 0;      if (!image) return 0;
2835    
# Line 1609  int updateActualImage(struct grubConfig Line 2856  int updateActualImage(struct grubConfig
2856   }   }
2857      }      }
2858    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2859    
2860      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2861   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2862    
2863      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2864   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2865    
2866      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2867    
2868      k = 0;   if (multibootArgs && !entry->multiboot)
2869      for (arg = newArgs; *arg; arg++)      continue;
2870          k++;  
2871      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2872     * LT_KERNELARGS, use that.  Otherwise use
2873     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2874     */
2875     if (useKernelArgs) {
2876        line = getLineByType(LT_KERNELARGS, entry->lines);
2877        if (!line) {
2878     /* no LT_KERNELARGS, need to add it */
2879     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2880           cfg->secondaryIndent, NULL);
2881        }
2882        firstElement = 1;
2883    
2884      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2885   index++;      line = getLineByType(LT_HYPER, entry->lines);
2886        if (!line) {
2887     /* a multiboot entry without LT_HYPER? */
2888     continue;
2889        }
2890        firstElement = 2;
2891    
2892   line = entry->lines;   } else {
2893   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
2894   if (!line) continue;      if (!line) {
2895   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2896     continue;
2897          if (entry->multiboot && !multibootArgs) {      }
2898              /* 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;  
2899   }   }
2900    
2901   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2902      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2903      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2904     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2905        /* this is a multiboot entry, make sure there's
2906         * -- on the args line
2907         */
2908        for (i = firstElement; i < line->numElements; i++) {
2909     if (!strcmp(line->elements[i].item, "--"))
2910        break;
2911        }
2912        if (i == line->numElements) {
2913     /* assume all existing args are kernel args,
2914     * prepend -- to make it official
2915     */
2916     insertElement(line, "--", firstElement, cfg->cfi);
2917     i = firstElement;
2918        }
2919        if (!multibootArgs) {
2920     /* kernel args start after the -- */
2921     firstElement = i + 1;
2922        }
2923     } else if (cfg->cfi->mbConcatArgs) {
2924        /* this is a non-multiboot entry, remove hyper args */
2925        for (i = firstElement; i < line->numElements; i++) {
2926     if (!strcmp(line->elements[i].item, "--"))
2927        break;
2928        }
2929        if (i < line->numElements) {
2930     /* remove args up to -- */
2931     while (strcmp(line->elements[firstElement].item, "--"))
2932        removeElement(line, firstElement);
2933     /* remove -- */
2934     removeElement(line, firstElement);
2935        }
2936   }   }
2937    
2938          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2939    
2940          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2941   for (arg = newArgs; *arg; arg++) {  
2942              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2943      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2944     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2945        !strcmp(line->elements[i].item, "--"))
2946     {
2947        /* reached the end of hyper args, insert here */
2948        doreplace = 0;
2949        break;  
2950     }
2951                  if (usedElements[i])                  if (usedElements[i])
2952                      continue;                      continue;
2953   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2954                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2955      break;      break;
2956                  }                  }
2957              }              }
     chptr = strchr(*arg, '=');  
2958    
2959      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2960   /* replace */   /* direct replacement */
2961   free(line->elements[i].item);   free(line->elements[i].item);
2962   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("");  
  }  
2963    
2964   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2965   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2966      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2967   /* append */   if (rootLine) {
2968   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2969   (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(" ");  
2970   } else {   } else {
2971      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2972         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2973   }   }
2974        }
2975    
2976   line->numElements++;      else {
2977     /* insert/append */
2978     insertElement(line, *arg, i, cfg->cfi);
2979     usedElements = realloc(usedElements, line->numElements *
2980           sizeof(*usedElements));
2981     memmove(&usedElements[i + 1], &usedElements[i],
2982     line->numElements - i - 1);
2983     usedElements[i] = 1;
2984    
2985   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2986     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2987     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2988   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2989      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2990      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2991   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2992   }   }
2993      }      }
             k++;  
2994   }   }
2995    
2996          free(usedElements);          free(usedElements);
2997    
  /* 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? */  
2998   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2999      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3000   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3001        !strcmp(line->elements[i].item, "--"))
3002        /* reached the end of hyper args, stop here */
3003        break;
3004     if (!argMatch(line->elements[i].item, *arg)) {
3005        removeElement(line, i);
3006      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;  
3007   }   }
3008        }
3009   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3010        if (useRoot && !strncmp(*arg, "root=", 5)) {
3011   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3012      line->elements[j - 1] = line->elements[j];   if (rootLine)
3013        removeLine(entry, rootLine);
  line->numElements--;  
3014      }      }
3015   }   }
3016    
# Line 1760  int updateActualImage(struct grubConfig Line 3021  int updateActualImage(struct grubConfig
3021   }   }
3022      }      }
3023    
     free(usedArgs);  
3024      free(newArgs);      free(newArgs);
3025      free(oldArgs);      free(oldArgs);
3026    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3046  int updateImage(struct grubConfig * cfg,
3046      return rc;      return rc;
3047  }  }
3048    
3049    int updateInitrd(struct grubConfig * cfg, const char * image,
3050                     const char * prefix, const char * initrd) {
3051        struct singleEntry * entry;
3052        struct singleLine * line, * kernelLine, *endLine = NULL;
3053        int index = 0;
3054    
3055        if (!image) return 0;
3056    
3057        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3058            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3059            if (!kernelLine) continue;
3060    
3061            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3062            if (line)
3063                removeLine(entry, line);
3064            if (prefix) {
3065                int prefixLen = strlen(prefix);
3066                if (!strncmp(initrd, prefix, prefixLen))
3067                    initrd += prefixLen;
3068            }
3069     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3070     if (endLine)
3071        removeLine(entry, endLine);
3072            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3073     kernelLine->indent, initrd);
3074            if (!line)
3075        return 1;
3076     if (endLine) {
3077        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3078                if (!line)
3079     return 1;
3080     }
3081    
3082            break;
3083        }
3084    
3085        return 0;
3086    }
3087    
3088  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3089      int fd;      int fd;
3090      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3108  int checkDeviceBootloader(const char * d
3108      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3109   return 0;   return 0;
3110    
3111      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3112   offset = boot[2] + 2;   offset = boot[2] + 2;
3113      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3114   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3115      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3116   offset = boot[1] + 2;        offset = boot[1] + 2;
3117            /*
3118     * it looks like grub, when copying stage1 into the mbr, patches stage1
3119     * right after the JMP location, replacing other instructions such as
3120     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3121     * different bytes.
3122     */
3123          if ((bootSect[offset + 1] == NOOP_OPCODE)
3124      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3125     offset = offset + 3;
3126          }
3127      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3128   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3129      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3265  int checkForLilo(struct grubConfig * con
3265      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3266  }  }
3267    
3268    int checkForGrub2(struct grubConfig * config) {
3269        if (!access("/etc/grub.d/", R_OK))
3270     return 2;
3271    
3272        return 1;
3273    }
3274    
3275  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3276      int fd;      int fd;
3277      unsigned char bootSect[512];      unsigned char bootSect[512];
3278      char * boot;      char * boot;
3279        int onSuse = isSuseSystem();
3280    
3281      if (parseSysconfigGrub(NULL, &boot))  
3282   return 0;      if (onSuse) {
3283     if (parseSuseGrubConf(NULL, &boot))
3284        return 0;
3285        } else {
3286     if (parseSysconfigGrub(NULL, &boot))
3287        return 0;
3288        }
3289    
3290      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3291      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3299  int checkForGrub(struct grubConfig * con
3299      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3300   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3301   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3302     close(fd);
3303   return 1;   return 1;
3304      }      }
3305      close(fd);      close(fd);
3306    
3307        /* The more elaborate checks do not work on SuSE. The checks done
3308         * seem to be reasonble (at least for now), so just return success
3309         */
3310        if (onSuse)
3311     return 2;
3312    
3313      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3314  }  }
3315    
3316    int checkForExtLinux(struct grubConfig * config) {
3317        int fd;
3318        unsigned char bootSect[512];
3319        char * boot;
3320        char executable[] = "/boot/extlinux/extlinux";
3321    
3322        printf("entered: checkForExtLinux()\n");
3323    
3324        if (parseSysconfigGrub(NULL, &boot))
3325     return 0;
3326    
3327        /* assume grub is not installed -- not an error condition */
3328        if (!boot)
3329     return 0;
3330    
3331        fd = open(executable, O_RDONLY);
3332        if (fd < 0)
3333     /* this doesn't exist if grub hasn't been installed */
3334     return 0;
3335    
3336        if (read(fd, bootSect, 512) != 512) {
3337     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3338     executable, strerror(errno));
3339     return 1;
3340        }
3341        close(fd);
3342    
3343        return checkDeviceBootloader(boot, bootSect);
3344    }
3345    
3346    int checkForYaboot(struct grubConfig * config) {
3347        /*
3348         * This is a simplistic check that we consider good enough for own puporses
3349         *
3350         * If we were to properly check if yaboot is *installed* we'd need to:
3351         * 1) get the system boot device (LT_BOOT)
3352         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3353         *    the content on the boot device
3354         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3355         * 4) check again if binary and boot device contents match
3356         */
3357        if (!access("/etc/yaboot.conf", R_OK))
3358     return 2;
3359    
3360        return 1;
3361    }
3362    
3363    int checkForElilo(struct grubConfig * config) {
3364        if (!access("/etc/elilo.conf", R_OK))
3365     return 2;
3366    
3367        return 1;
3368    }
3369    
3370  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3371      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3372    
# Line 1994  static char * getRootSpecifier(char * st Line 3378  static char * getRootSpecifier(char * st
3378      return rootspec;      return rootspec;
3379  }  }
3380    
3381    static char * getInitrdVal(struct grubConfig * config,
3382       const char * prefix, struct singleLine *tmplLine,
3383       const char * newKernelInitrd,
3384       const char ** extraInitrds, int extraInitrdCount)
3385    {
3386        char *initrdVal, *end;
3387        int i;
3388        size_t totalSize;
3389        size_t prefixLen;
3390        char separatorChar;
3391    
3392        prefixLen = strlen(prefix);
3393        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3394    
3395        for (i = 0; i < extraInitrdCount; i++) {
3396     totalSize += sizeof(separatorChar);
3397     totalSize += strlen(extraInitrds[i]) - prefixLen;
3398        }
3399    
3400        initrdVal = end = malloc(totalSize);
3401    
3402        end = stpcpy (end, newKernelInitrd + prefixLen);
3403    
3404        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3405        for (i = 0; i < extraInitrdCount; i++) {
3406     const char *extraInitrd;
3407     int j;
3408    
3409     extraInitrd = extraInitrds[i] + prefixLen;
3410     /* Don't add entries that are already there */
3411     if (tmplLine != NULL) {
3412        for (j = 2; j < tmplLine->numElements; j++)
3413     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3414        break;
3415    
3416        if (j != tmplLine->numElements)
3417     continue;
3418     }
3419    
3420     *end++ = separatorChar;
3421     end = stpcpy(end, extraInitrd);
3422        }
3423    
3424        return initrdVal;
3425    }
3426    
3427  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3428           const char * prefix,           const char * prefix,
3429   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3430   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3431                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3432                     const char * newMBKernel, const char * newMBKernelArgs) {
3433      struct singleEntry * new;      struct singleEntry * new;
3434      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3435      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3436      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3437    
3438      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3439    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3463  int addNewKernel(struct grubConfig * con
3463      config->entries = new;      config->entries = new;
3464    
3465      /* copy/update from the template */      /* copy/update from the template */
3466      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3467        if (newKernelInitrd)
3468     needs |= NEED_INITRD;
3469      if (newMBKernel) {      if (newMBKernel) {
3470          needs |= KERNEL_MB;          needs |= NEED_MB;
3471          new->multiboot = 1;          new->multiboot = 1;
3472      }      }
3473    
3474      if (template) {      if (template) {
3475   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3476      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3477      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3478   indent = tmplLine->indent;   {
3479        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3480    
3481      /* skip comments */      /* skip comments */
3482      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3483      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3484      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3485    
3486      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3487      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3488        /* it's not a multiboot template and this is the kernel
3489              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3490                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3491                  struct singleLine *l;       */
3492                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3493     /* insert the hypervisor first */
3494                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3495                                    config->secondaryIndent,    tmplLine->indent,
3496                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3497                     /* set up for adding the kernel line */
3498                  tmplLine = lastLine;   free(tmplLine->indent);
3499                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3500                      new->lines = l;   needs &= ~NEED_MB;
3501                  } else {      }
3502                      newLine->next = l;      if (needs & NEED_KERNEL) {
3503                      newLine = l;   /* use addLineTmpl to preserve line elements,
3504                  }   * otherwise we could just call addLine.  Unfortunately
3505                  continue;   * this means making some changes to the template
3506              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3507                         template->multiboot && !new->multiboot) {   * change below.
3508                  continue; /* don't need multiboot kernel here */   */
3509              }   struct keywordTypes * mbm_kw =
3510        getKeywordByType(LT_MBMODULE, config->cfi);
3511      if (!new->lines) {   if (mbm_kw) {
3512   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3513   new->lines = newLine;      free(tmplLine->elements[0].item);
3514      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3515   newLine->next = malloc(sizeof(*newLine));   }
3516   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3517      }        newKernelPath + strlen(prefix), config->cfi);
3518     needs &= ~NEED_KERNEL;
3519        }
3520        if (needs & NEED_MB) { /* !mbHyperFirst */
3521     newLine = addLine(new, config->cfi, LT_HYPER,
3522      config->secondaryIndent,
3523      newMBKernel + strlen(prefix));
3524     needs &= ~NEED_MB;
3525        }
3526     } else if (needs & NEED_KERNEL) {
3527        newLine = addLineTmpl(new, tmplLine, newLine,
3528      newKernelPath + strlen(prefix), config->cfi);
3529        needs &= ~NEED_KERNEL;
3530     }
3531    
3532        } else if (tmplLine->type == LT_HYPER &&
3533           tmplLine->numElements >= 2) {
3534     if (needs & NEED_MB) {
3535        newLine = addLineTmpl(new, tmplLine, newLine,
3536      newMBKernel + strlen(prefix), config->cfi);
3537        needs &= ~NEED_MB;
3538     }
3539    
3540      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3541      newLine->next = NULL;         tmplLine->numElements >= 2) {
3542      newLine->type = tmplLine->type;   if (new->multiboot) {
3543      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3544      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3545      newLine->numElements);        newKernelPath +
3546      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3547   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3548   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3549   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3550      }   char *initrdVal;
3551     initrdVal = getInitrdVal(config, prefix, tmplLine,
3552              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3553      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3554                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3555                  if (!template->multiboot) {        initrdVal, config->cfi);
3556                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3557                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3558                  } else {      }
3559                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3560                      repl = newMBKernel;      /* template is multi but new is not,
3561                  }       * insert the kernel in the first module slot
3562                  if (new->multiboot && !template->multiboot) {       */
3563                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3564                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3565                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3566                  }   strdup(getKeywordByType(tmplLine->type,
3567   free(newLine->elements[1].item);   config->cfi)->key);
3568                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3569                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3570                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3571                                                             rootspec,      needs &= ~NEED_KERNEL;
3572                                                             repl +   } else if (needs & NEED_INITRD) {
3573                                                             strlen(prefix));      char *initrdVal;
3574                  } else {      /* template is multi but new is not,
3575                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3576                                                         strlen(prefix));       */
3577                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3578              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3579                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3580                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3581                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3582                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3583                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3584                      newLine->type = LT_KERNEL;      free(initrdVal);
3585                  }      needs &= ~NEED_INITRD;
3586   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;  
3587    
3588   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3589      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3590      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3591        config->cfi->mbInitRdIsModule) {
3592        /* make sure we don't insert the module initrd
3593         * before the module kernel... if we don't do it here,
3594         * it will be inserted following the template.
3595         */
3596        if (!needs & NEED_KERNEL) {
3597     char *initrdVal;
3598    
3599     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3600     newLine = addLine(new, config->cfi, LT_MBMODULE,
3601      config->secondaryIndent,
3602      initrdVal);
3603     free(initrdVal);
3604     needs &= ~NEED_INITRD;
3605        }
3606     } else if (needs & NEED_INITRD) {
3607        char *initrdVal;
3608        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3609        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3610        free(initrdVal);
3611        needs &= ~NEED_INITRD;
3612   }   }
3613    
3614   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3615   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3616   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3617     char *nkt = malloc(strlen(newKernelTitle)+3);
3618     strcpy(nkt, "'");
3619     strcat(nkt, newKernelTitle);
3620     strcat(nkt, "'");
3621     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3622     free(nkt);
3623     needs &= ~NEED_TITLE;
3624      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3625                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3626                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3627                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3628                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3629                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3630                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3631                                             newLine->numElements);     config->cfi->titleBracketed) {
3632        /* addLineTmpl doesn't handle titleBracketed */
3633                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3634                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3635                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3636                  newLine->numElements = 1;   }
3637              }      } else if (tmplLine->type == LT_ECHO) {
3638        requote(tmplLine, config->cfi);
3639        static const char *prefix = "'Loading ";
3640        if (tmplLine->numElements > 1 &&
3641        strstr(tmplLine->elements[1].item, prefix) &&
3642        masterLine->next &&
3643        iskernel(masterLine->next->type)) {
3644     char *newTitle = malloc(strlen(prefix) +
3645     strlen(newKernelTitle) + 2);
3646    
3647     strcpy(newTitle, prefix);
3648     strcat(newTitle, newKernelTitle);
3649     strcat(newTitle, "'");
3650     newLine = addLine(new, config->cfi, LT_ECHO,
3651     tmplLine->indent, newTitle);
3652     free(newTitle);
3653        } else {
3654     /* pass through other lines from the template */
3655     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3656     config->cfi);
3657        }
3658        } else {
3659     /* pass through other lines from the template */
3660     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3661        }
3662   }   }
3663    
3664      } else {      } else {
3665   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3666      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3667     */
3668     switch (config->cfi->entryStart) {
3669        case LT_KERNEL:
3670        case LT_KERNEL_EFI:
3671     if (new->multiboot && config->cfi->mbHyperFirst) {
3672        /* fall through to LT_HYPER */
3673     } else {
3674        newLine = addLine(new, config->cfi,
3675              preferredLineType(LT_KERNEL, config->cfi),
3676          config->primaryIndent,
3677          newKernelPath + strlen(prefix));
3678        needs &= ~NEED_KERNEL;
3679        break;
3680     }
3681    
3682        case LT_HYPER:
3683     newLine = addLine(new, config->cfi, LT_HYPER,
3684      config->primaryIndent,
3685      newMBKernel + strlen(prefix));
3686     needs &= ~NEED_MB;
3687   break;   break;
         }  
3688    
3689   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3690      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3691       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3692       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3693      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3694       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3695      default:        config->primaryIndent, nkt);
3696                  /* zipl strikes again */   free(nkt);
3697                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3698                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3699                      chptr = newKernelTitle;   break;
3700                      type = LT_TITLE;      }
3701                      break;      case LT_TITLE:
3702                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3703                      abort();   char * templabel;
3704                  }   int x = 0, y = 0;
3705   }  
3706     templabel = strdup(newKernelTitle);
3707     while( templabel[x]){
3708     if( templabel[x] == ' ' ){
3709     y = x;
3710     while( templabel[y] ){
3711     templabel[y] = templabel[y+1];
3712     y++;
3713     }
3714     }
3715     x++;
3716     }
3717     newLine = addLine(new, config->cfi, LT_TITLE,
3718      config->primaryIndent, templabel);
3719     free(templabel);
3720     }else{
3721     newLine = addLine(new, config->cfi, LT_TITLE,
3722      config->primaryIndent, newKernelTitle);
3723     }
3724     needs &= ~NEED_TITLE;
3725     break;
3726    
3727   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3728   new->lines = newLine;   abort();
3729     }
3730      }      }
3731    
3732      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3733          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3734              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3735                                config->secondaryIndent,       */
3736                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3737          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3738              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3739                                config->secondaryIndent,    newKernelTitle);
3740                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3741          /* don't need to check for title as it's guaranteed to have been      }
3742           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3743           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3744          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3745              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3746                                config->secondaryIndent,   needs &= ~NEED_MB;
3747                                newKernelInitrd + strlen(prefix));      }
3748      } else {      if (needs & NEED_KERNEL) {
3749          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3750              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3751                                config->secondaryIndent,        config->cfi))
3752                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3753          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3754              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3755                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3756                                newKernelTitle);   needs &= ~NEED_KERNEL;
3757          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3758              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3759                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3760                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3761      newMBKernel + strlen(prefix));
3762     needs &= ~NEED_MB;
3763        }
3764        if (needs & NEED_INITRD) {
3765     char *initrdVal;
3766     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3767     newLine = addLine(new, config->cfi,
3768      (new->multiboot && getKeywordByType(LT_MBMODULE,
3769          config->cfi))
3770       ? LT_MBMODULE
3771       : preferredLineType(LT_INITRD, config->cfi),
3772      config->secondaryIndent,
3773      initrdVal);
3774     free(initrdVal);
3775     needs &= ~NEED_INITRD;
3776        }
3777        if (needs & NEED_END) {
3778     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3779     config->secondaryIndent, NULL);
3780     needs &= ~NEED_END;
3781        }
3782    
3783        if (needs) {
3784     printf(_("grubby: needs=%d, aborting\n"), needs);
3785     abort();
3786      }      }
3787    
3788      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3791  int addNewKernel(struct grubConfig * con
3791      return 0;      return 0;
3792  }  }
3793    
3794    static void traceback(int signum)
3795    {
3796        void *array[40];
3797        size_t size;
3798    
3799        signal(SIGSEGV, SIG_DFL);
3800        memset(array, '\0', sizeof (array));
3801        size = backtrace(array, 40);
3802    
3803        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
3804                (unsigned long)size);
3805        backtrace_symbols_fd(array, size, STDERR_FILENO);
3806        exit(1);
3807    }
3808    
3809  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3810      poptContext optCon;      poptContext optCon;
3811      char * grubConfig = NULL;      const char * grubConfig = NULL;
3812      char * outputFile = NULL;      char * outputFile = NULL;
3813      int arg = 0;      int arg = 0;
3814      int flags = 0;      int flags = 0;
3815      int badImageOkay = 0;      int badImageOkay = 0;
3816        int configureGrub2 = 0;
3817      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3818      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3819        int configureExtLinux = 0;
3820      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3821        int extraInitrdCount = 0;
3822      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3823      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3824      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3834  int main(int argc, const char ** argv) {
3834      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3835      char * removeArgs = NULL;      char * removeArgs = NULL;
3836      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3837        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3838      const char * chptr = NULL;      const char * chptr = NULL;
3839      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3840      struct grubConfig * config;      struct grubConfig * config;
3841      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3842      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3843      int displayDefault = 0;      int displayDefault = 0;
3844        int displayDefaultIndex = 0;
3845        int displayDefaultTitle = 0;
3846        int defaultIndex = -1;
3847      struct poptOption options[] = {      struct poptOption options[] = {
3848   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3849      _("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 3861  int main(int argc, const char ** argv) {
3861   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3862      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3863      _("bootfs") },      _("bootfs") },
3864  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3865   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3866      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3867  #endif  #endif
3868   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3869      _("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 3874  int main(int argc, const char ** argv) {
3874        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3875        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3876        "template"), NULL },        "template"), NULL },
3877     { "debug", 0, 0, &debug, 0,
3878        _("print debugging information for failures") },
3879   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3880      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3881     { "default-index", 0, 0, &displayDefaultIndex, 0,
3882        _("display the index of the default kernel") },
3883     { "default-title", 0, 0, &displayDefaultTitle, 0,
3884        _("display the title of the default kernel") },
3885   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3886      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3887     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
3888        _("force grub2 stanzas to use efi") },
3889     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3890        _("configure extlinux bootloader (from syslinux)") },
3891   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3892      _("configure grub bootloader") },      _("configure grub bootloader") },
3893     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3894        _("configure grub2 bootloader") },
3895   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3896      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3897      _("kernel-path") },      _("kernel-path") },
3898   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3899      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3900     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3901        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
3902   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3903      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3904   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3918  int main(int argc, const char ** argv) {
3918   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3919      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3920        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3921     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3922        _("make the given entry index the default entry"),
3923        _("entry-index") },
3924   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3925      _("configure silo bootloader") },      _("configure silo bootloader") },
3926   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3938  int main(int argc, const char ** argv) {
3938   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3939      };      };
3940    
3941        useextlinuxmenu=0;
3942    
3943        signal(SIGSEGV, traceback);
3944    
3945        int i = 0;
3946        for (int j = 1; j < argc; j++)
3947     i += strlen(argv[j]) + 1;
3948        saved_command_line = malloc(i);
3949        if (!saved_command_line) {
3950     fprintf(stderr, "grubby: %m\n");
3951     exit(1);
3952        }
3953        saved_command_line[0] = '\0';
3954        for (int j = 1; j < argc; j++) {
3955     strcat(saved_command_line, argv[j]);
3956     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
3957        }
3958    
3959      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3960      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3961    
# Line 2391  int main(int argc, const char ** argv) { Line 3965  int main(int argc, const char ** argv) {
3965      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3966      exit(0);      exit(0);
3967      break;      break;
3968      case 'i':
3969        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3970         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3971        } else {
3972     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3973     return 1;
3974        }
3975        break;
3976   }   }
3977      }      }
3978    
# Line 2406  int main(int argc, const char ** argv) { Line 3988  int main(int argc, const char ** argv) {
3988   return 1;   return 1;
3989      }      }
3990    
3991      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3992   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3993     configureExtLinux ) > 1) {
3994   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3995   return 1;   return 1;
3996      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3997   fprintf(stderr,   fprintf(stderr,
3998      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3999   return 1;   return 1;
4000        } else if (configureGrub2) {
4001     cfi = &grub2ConfigType;
4002      } else if (configureLilo) {      } else if (configureLilo) {
4003   cfi = &liloConfigType;   cfi = &liloConfigType;
4004      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4011  int main(int argc, const char ** argv) {
4011          cfi = &siloConfigType;          cfi = &siloConfigType;
4012      } else if (configureZipl) {      } else if (configureZipl) {
4013          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4014        } else if (configureExtLinux) {
4015     cfi = &extlinuxConfigType;
4016     useextlinuxmenu=1;
4017      }      }
4018    
4019      if (!cfi) {      if (!cfi) {
4020            if (grub2FindConfig(&grub2ConfigType))
4021        cfi = &grub2ConfigType;
4022     else
4023        #ifdef __ia64__        #ifdef __ia64__
4024   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4025        #elif __powerpc__        #elif __powerpc__
4026   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4027        #elif __sparc__        #elif __sparc__
4028          cfi = &siloConfigType;              cfi = &siloConfigType;
4029        #elif __s390__        #elif __s390__
4030          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4031        #elif __s390x__        #elif __s390x__
4032          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4033        #else        #else
4034   cfi = &grubConfigType;      cfi = &grubConfigType;
4035        #endif        #endif
4036      }      }
4037    
4038      if (!grubConfig)      if (!grubConfig) {
4039   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4040        grubConfig = cfi->findConfig(cfi);
4041     if (!grubConfig)
4042        grubConfig = cfi->defaultConfig;
4043        }
4044    
4045      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4046    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4047    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4048        (defaultIndex >= 0))) {
4049   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4050    "specified option"));    "specified option"));
4051   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4061  int main(int argc, const char ** argv) {
4061      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4062   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4063   return 1;   return 1;
4064      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4065    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4066    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4067   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4068   return 1;   return 1;
4069      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4087  int main(int argc, const char ** argv) {
4087   makeDefault = 1;   makeDefault = 1;
4088   defaultKernel = NULL;   defaultKernel = NULL;
4089      }      }
4090        else if (defaultKernel && (defaultIndex >= 0)) {
4091     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4092      "may not be used together\n"));
4093     return 1;
4094        }
4095    
4096      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4097   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4098   "is used\n"));   "is used\n"));
4099   return 1;   return 1;
4100      }      }
4101    
4102      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4103   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4104          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4105     && (defaultIndex == -1)) {
4106   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4107   return 1;   return 1;
4108      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4122  int main(int argc, const char ** argv) {
4122   bootPrefix = "";   bootPrefix = "";
4123      }      }
4124    
4125        if (!cfi->mbAllowExtraInitRds &&
4126     extraInitrdCount > 0) {
4127     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4128     return 1;
4129        }
4130    
4131      if (bootloaderProbe) {      if (bootloaderProbe) {
4132   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4133   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4134    
4135   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4136      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
4137        gconfig = readConfig(grub2config, &grub2ConfigType);
4138        if (!gconfig)
4139     gr2c = 1;
4140        else
4141     gr2c = checkForGrub2(gconfig);
4142     }
4143    
4144     const char *grubconfig = grubFindConfig(&grubConfigType);
4145     if (!access(grubconfig, F_OK)) {
4146        gconfig = readConfig(grubconfig, &grubConfigType);
4147      if (!gconfig)      if (!gconfig)
4148   grc = 1;   grc = 1;
4149      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4158  int main(int argc, const char ** argv) {
4158   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4159   }   }
4160    
4161   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4162        econfig = readConfig(eliloConfigType.defaultConfig,
4163     &eliloConfigType);
4164        if (!econfig)
4165     erc = 1;
4166        else
4167     erc = checkForElilo(econfig);
4168     }
4169    
4170     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4171        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4172        if (!lconfig)
4173     extrc = 1;
4174        else
4175     extrc = checkForExtLinux(lconfig);
4176     }
4177    
4178    
4179     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4180        yconfig = readConfig(yabootConfigType.defaultConfig,
4181     &yabootConfigType);
4182        if (!yconfig)
4183     yrc = 1;
4184        else
4185     yrc = checkForYaboot(yconfig);
4186     }
4187    
4188     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4189     erc == 1)
4190        return 1;
4191    
4192   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4193     if (gr2c == 2) printf("grub2\n");
4194   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4195     if (extrc == 2) printf("extlinux\n");
4196     if (yrc == 2) printf("yaboot\n");
4197     if (erc == 2) printf("elilo\n");
4198    
4199   return 0;   return 0;
4200      }      }
4201    
4202        if (grubConfig == NULL) {
4203     printf("Could not find bootloader configuration file.\n");
4204     exit(1);
4205        }
4206    
4207      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4208      if (!config) return 1;      if (!config) return 1;
4209    
# Line 2561  int main(int argc, const char ** argv) { Line 4217  int main(int argc, const char ** argv) {
4217   if (!entry) return 0;   if (!entry) return 0;
4218   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4219    
4220   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4221   if (!line) return 0;   if (!line) return 0;
4222    
4223          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4225  int main(int argc, const char ** argv) {
4225                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4226    
4227   return 0;   return 0;
4228    
4229        } else if (displayDefaultTitle) {
4230     struct singleLine * line;
4231     struct singleEntry * entry;
4232    
4233     if (config->defaultImage == -1) return 0;
4234     entry = findEntryByIndex(config, config->defaultImage);
4235     if (!entry) return 0;
4236    
4237     if (!configureGrub2) {
4238      line = getLineByType(LT_TITLE, entry->lines);
4239      if (!line) return 0;
4240      printf("%s\n", line->elements[1].item);
4241    
4242     } else {
4243      char * title;
4244    
4245      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4246      line = getLineByType(LT_MENUENTRY, entry->lines);
4247      if (!line) return 0;
4248      title = grub2ExtractTitle(line);
4249      if (title)
4250        printf("%s\n", title);
4251     }
4252     return 0;
4253    
4254        } else if (displayDefaultIndex) {
4255            if (config->defaultImage == -1) return 0;
4256            printf("%i\n", config->defaultImage);
4257            return 0;
4258    
4259      } else if (kernelInfo)      } else if (kernelInfo)
4260   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4261    
# Line 2581  int main(int argc, const char ** argv) { Line 4267  int main(int argc, const char ** argv) {
4267      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4268      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4269      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4270      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4271      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4272      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4273                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4274        if (updateKernelPath && newKernelInitrd) {
4275                if (updateInitrd(config, updateKernelPath, bootPrefix,
4276                                 newKernelInitrd)) return 1;
4277        }
4278      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4279                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4280                         (const char **)extraInitrds, extraInitrdCount,
4281                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4282            
4283    
# Line 2597  int main(int argc, const char ** argv) { Line 4288  int main(int argc, const char ** argv) {
4288      }      }
4289    
4290      if (!outputFile)      if (!outputFile)
4291   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4292    
4293      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4294  }  }

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