Magellan Linux

Diff of /tags/grubby-8_18/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 1800 by niro, Mon Apr 16 17:46:40 2012 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39    #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43  #include "mount_by_label.h"  #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49    int debug = 0; /* Currently just for template debugging */
50    
51  #define _(A) (A)  #define _(A) (A)
52    
53    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
54  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
55    
56    #define NOOP_OPCODE 0x90
57    #define JMP_SHORT_OPCODE 0xeb
58    
59  /* comments get lumped in with indention */  /* comments get lumped in with indention */
60  struct lineElement {  struct lineElement {
61      char * item;      char * item;
62      char * indent;      char * indent;
63  };  };
64    
65  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
66         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
67         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
68        LT_KERNEL       = 1 << 2,
69        LT_INITRD       = 1 << 3,
70        LT_HYPER        = 1 << 4,
71        LT_DEFAULT      = 1 << 5,
72        LT_MBMODULE     = 1 << 6,
73        LT_ROOT         = 1 << 7,
74        LT_FALLBACK     = 1 << 8,
75        LT_KERNELARGS   = 1 << 9,
76        LT_BOOT         = 1 << 10,
77        LT_BOOTROOT     = 1 << 11,
78        LT_LBA          = 1 << 12,
79        LT_OTHER        = 1 << 13,
80        LT_GENERIC      = 1 << 14,
81        LT_ECHO    = 1 << 16,
82        LT_MENUENTRY    = 1 << 17,
83        LT_ENTRY_END    = 1 << 18,
84        LT_SET_VARIABLE = 1 << 19,
85        LT_UNKNOWN      = 1 << 20,
86    };
87    
88  struct singleLine {  struct singleLine {
89      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 104  struct singleEntry {
104    
105  #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 */
106    
107  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
108  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
109  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
110  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
111  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
112    #define NEED_MB      (1 << 4)
113    #define NEED_END     (1 << 5)
114    
115  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
116  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
117    #define DEFAULT_SAVED_GRUB2 -3
118    
119  struct keywordTypes {  struct keywordTypes {
120      char * key;      char * key;
121      enum lineType_e type;      enum lineType_e type;
122      char nextChar;      char nextChar;
123  } ;      char separatorChar;
124    };
125    
126    struct configFileInfo;
127    
128    typedef const char *(*findConfigFunc)(struct configFileInfo *);
129    typedef const int (*writeLineFunc)(struct configFileInfo *,
130     struct singleLine *line);
131    
132  struct configFileInfo {  struct configFileInfo {
133      char * defaultConfig;      char * defaultConfig;
134        findConfigFunc findConfig;
135        writeLineFunc writeLine;
136      struct keywordTypes * keywords;      struct keywordTypes * keywords;
137      int defaultIsIndex;      int defaultIsIndex;
138        int defaultIsVariable;
139      int defaultSupportSaved;      int defaultSupportSaved;
140      enum lineType_e entrySeparator;      enum lineType_e entryStart;
141        enum lineType_e entryEnd;
142      int needsBootPrefix;      int needsBootPrefix;
143      int argsInQuotes;      int argsInQuotes;
144      int maxTitleLength;      int maxTitleLength;
145      int titleBracketed;      int titleBracketed;
146        int titlePosition;
147        int mbHyperFirst;
148        int mbInitRdIsModule;
149        int mbConcatArgs;
150        int mbAllowExtraInitRds;
151  };  };
152    
153  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 156  struct keywordTypes grubKeywords[] = {
156      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
157      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
158      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
159      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
160      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
161        { "kernel",     LT_HYPER,       ' ' },
162      { NULL,    0, 0 },      { NULL,    0, 0 },
163  };  };
164    
165    const char *grubFindConfig(struct configFileInfo *cfi) {
166        static const char *configFiles[] = {
167     "/etc/grub.conf",
168     "/boot/grub/grub.conf",
169     "/boot/grub/menu.lst",
170     NULL
171        };
172        static int i = -1;
173    
174        if (i == -1) {
175     for (i = 0; configFiles[i] != NULL; i++) {
176        dbgPrintf("Checking \"%s\": ", configFiles[i]);
177        if (!access(configFiles[i], R_OK)) {
178     dbgPrintf("found\n");
179     return configFiles[i];
180        }
181        dbgPrintf("not found\n");
182     }
183        }
184        return configFiles[i];
185    }
186    
187  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
188      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
189      grubKeywords,    /* keywords */      .keywords = grubKeywords,
190      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
191      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
192      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
193      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
194      0,    /* argsInQuotes */      .mbHyperFirst = 1,
195      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
196      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
197    };
198    
199    struct keywordTypes grub2Keywords[] = {
200        { "menuentry",  LT_MENUENTRY,   ' ' },
201        { "}",          LT_ENTRY_END,   ' ' },
202        { "echo",       LT_ECHO,        ' ' },
203        { "set",        LT_SET_VARIABLE,' ', '=' },
204        { "root",       LT_BOOTROOT,    ' ' },
205        { "default",    LT_DEFAULT,     ' ' },
206        { "fallback",   LT_FALLBACK,    ' ' },
207        { "linux",      LT_KERNEL,      ' ' },
208        { "initrd",     LT_INITRD,      ' ', ' ' },
209        { "module",     LT_MBMODULE,    ' ' },
210        { "kernel",     LT_HYPER,       ' ' },
211        { NULL, 0, 0 },
212    };
213    
214    const char *grub2FindConfig(struct configFileInfo *cfi) {
215        static const char *configFiles[] = {
216     "/boot/grub/grub-efi.cfg",
217     "/boot/grub/grub.cfg",
218     NULL
219        };
220        static int i = -1;
221        static const char *grub_cfg = "/boot/grub/grub.cfg";
222    
223        if (i == -1) {
224     for (i = 0; configFiles[i] != NULL; i++) {
225        dbgPrintf("Checking \"%s\": ", configFiles[i]);
226        if (!access(configFiles[i], R_OK)) {
227     dbgPrintf("found\n");
228     return configFiles[i];
229        }
230     }
231        }
232    
233        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
234         * that isn't in grub1, and if it exists, return the config file path
235         * that they use. */
236        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
237     dbgPrintf("found\n");
238     return grub_cfg;
239        }
240    
241        dbgPrintf("not found\n");
242        return configFiles[i];
243    }
244    
245    int sizeOfSingleLine(struct singleLine * line) {
246      int i;
247      int count = 0;
248    
249      for (i = 0; i < line->numElements; i++) {
250        int indentSize = 0;
251    
252        count = count + strlen(line->elements[i].item);
253    
254        indentSize = strlen(line->elements[i].indent);
255        if (indentSize > 0)
256          count = count + indentSize;
257        else
258          /* be extra safe and add room for whitespaces */
259          count = count + 1;
260      }
261    
262      /* room for trailing terminator */
263      count = count + 1;
264    
265      return count;
266    }
267    
268    static int isquote(char q)
269    {
270        if (q == '\'' || q == '\"')
271     return 1;
272        return 0;
273    }
274    
275    char *grub2ExtractTitle(struct singleLine * line) {
276        char * current;
277        char * current_indent;
278        int current_len;
279        int current_indent_len;
280        int i;
281    
282        /* bail out if line does not start with menuentry */
283        if (strcmp(line->elements[0].item, "menuentry"))
284          return NULL;
285    
286        i = 1;
287        current = line->elements[i].item;
288        current_len = strlen(current);
289    
290        /* if second word is quoted, strip the quotes and return single word */
291        if (isquote(*current) && isquote(current[current_len - 1])) {
292     char *tmp;
293    
294     tmp = strdup(current);
295     *(tmp + current_len - 1) = '\0';
296     return ++tmp;
297        }
298    
299        /* if no quotes, return second word verbatim */
300        if (!isquote(*current))
301     return current;
302    
303        /* second element start with a quote, so we have to find the element
304         * whose last character is also quote (assuming it's the closing one) */
305        int resultMaxSize;
306        char * result;
307        
308        resultMaxSize = sizeOfSingleLine(line);
309        result = malloc(resultMaxSize);
310        snprintf(result, resultMaxSize, "%s", ++current);
311        
312        i++;
313        for (; i < line->numElements; ++i) {
314     current = line->elements[i].item;
315     current_len = strlen(current);
316     current_indent = line->elements[i].indent;
317     current_indent_len = strlen(current_indent);
318    
319     strncat(result, current_indent, current_indent_len);
320     if (!isquote(current[current_len-1])) {
321        strncat(result, current, current_len);
322     } else {
323        strncat(result, current, current_len - 1);
324        break;
325     }
326        }
327        return result;
328    }
329    
330    struct configFileInfo grub2ConfigType = {
331        .findConfig = grub2FindConfig,
332        .keywords = grub2Keywords,
333        .defaultIsIndex = 1,
334        .defaultSupportSaved = 1,
335        .defaultIsVariable = 1,
336        .entryStart = LT_MENUENTRY,
337        .entryEnd = LT_ENTRY_END,
338        .titlePosition = 1,
339        .needsBootPrefix = 1,
340        .mbHyperFirst = 1,
341        .mbInitRdIsModule = 1,
342        .mbAllowExtraInitRds = 1,
343  };  };
344    
345  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 373  struct keywordTypes yabootKeywords[] = {
373      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
374      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
375      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
376      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
377      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
378      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
379      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 393  struct keywordTypes liloKeywords[] = {
393      { NULL,    0, 0 },      { NULL,    0, 0 },
394  };  };
395    
396    struct keywordTypes eliloKeywords[] = {
397        { "label",    LT_TITLE,    '=' },
398        { "root",    LT_ROOT,    '=' },
399        { "default",    LT_DEFAULT,    '=' },
400        { "image",    LT_KERNEL,    '=' },
401        { "initrd",    LT_INITRD,    '=' },
402        { "append",    LT_KERNELARGS,  '=' },
403        { "vmm",    LT_HYPER,       '=' },
404        { NULL,    0, 0 },
405    };
406    
407  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
408      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
409      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 425  struct keywordTypes ziplKeywords[] = {
425      { NULL,         0, 0 },      { NULL,         0, 0 },
426  };  };
427    
428    struct keywordTypes extlinuxKeywords[] = {
429        { "label",    LT_TITLE,    ' ' },
430        { "root",    LT_ROOT,    ' ' },
431        { "default",    LT_DEFAULT,    ' ' },
432        { "kernel",    LT_KERNEL,    ' ' },
433        { "initrd",    LT_INITRD,      ' ', ',' },
434        { "append",    LT_KERNELARGS,  ' ' },
435        { "prompt",     LT_UNKNOWN,     ' ' },
436        { NULL,    0, 0 },
437    };
438    int useextlinuxmenu;
439  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
440      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
441      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
442      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
443      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
444      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
445      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
446  };  };
447    
448  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
449      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
450      liloKeywords,    /* keywords */      .keywords = liloKeywords,
451      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
452      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
453      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
454  };  };
455    
456  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
457      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
458      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
459      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
460      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
461      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
462      1,    /* needsBootPrefix */      .maxTitleLength = 15,
463      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
464  };  };
465    
466  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
467      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
468      siloKeywords,    /* keywords */      .keywords = siloKeywords,
469      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
470      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
471      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
472      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
473  };  };
474    
475  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
476      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
477      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
478      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
479      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
480      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
481      0,    /* needsBootPrefix */  };
482      1,    /* argsInQuotes */  
483      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
484      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
485        .keywords = extlinuxKeywords,
486        .entryStart = LT_TITLE,
487        .needsBootPrefix = 1,
488        .maxTitleLength = 255,
489        .mbAllowExtraInitRds = 1,
490  };  };
491    
492  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 501  struct grubConfig {
501      struct configFileInfo * cfi;      struct configFileInfo * cfi;
502  };  };
503    
504    blkid_cache blkid;
505    
506  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
507  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
508       const char * path, const char * prefix,       const char * path, const char * prefix,
509       int * index);       int * index);
 static char * strndup(char * from, int len);  
510  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
511  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
512    struct singleLine * lineDup(struct singleLine * line);
513  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
514  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
515       struct configFileInfo * cfi);       struct configFileInfo * cfi);
516  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
517         struct configFileInfo * cfi);         struct configFileInfo * cfi);
518  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
519    static void requote(struct singleLine *line, struct configFileInfo * cfi);
520  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
521      char * to;    const char * item, int insertHere,
522      struct configFileInfo * cfi);
523      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
524      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
525      to[len] = '\0';        struct configFileInfo * cfi);
526    static enum lineType_e getTypeByKeyword(char * keyword,
527      return to;   struct configFileInfo * cfi);
528  }  static struct singleLine * getLineByType(enum lineType_e type,
529     struct singleLine * line);
530    static int checkForExtLinux(struct grubConfig * config);
531    struct singleLine * addLineTmpl(struct singleEntry * entry,
532                                    struct singleLine * tmplLine,
533                                    struct singleLine * prevLine,
534                                    const char * val,
535     struct configFileInfo * cfi);
536    struct singleLine *  addLine(struct singleEntry * entry,
537                                 struct configFileInfo * cfi,
538                                 enum lineType_e type, char * defaultIndent,
539                                 const char * val);
540    
541  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
542  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 571  static char * sdupprintf(const char *for
571      return buf;      return buf;
572  }  }
573    
574    static struct keywordTypes * getKeywordByType(enum lineType_e type,
575          struct configFileInfo * cfi) {
576        struct keywordTypes * kw;
577        for (kw = cfi->keywords; kw->key; kw++) {
578     if (kw->type == type)
579        return kw;
580        }
581        return NULL;
582    }
583    
584    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
585        struct keywordTypes *kt = getKeywordByType(type, cfi);
586        if (kt)
587     return kt->key;
588        return "unknown";
589    }
590    
591    static char * getpathbyspec(char *device) {
592        if (!blkid)
593            blkid_get_cache(&blkid, NULL);
594    
595        return blkid_get_devname(blkid, device, NULL);
596    }
597    
598    static char * getuuidbydev(char *device) {
599        if (!blkid)
600     blkid_get_cache(&blkid, NULL);
601    
602        return blkid_get_tag_value(blkid, "UUID", device);
603    }
604    
605    static enum lineType_e getTypeByKeyword(char * keyword,
606     struct configFileInfo * cfi) {
607        struct keywordTypes * kw;
608        for (kw = cfi->keywords; kw->key; kw++) {
609     if (!strcmp(keyword, kw->key))
610        return kw->type;
611        }
612        return LT_UNKNOWN;
613    }
614    
615    static struct singleLine * getLineByType(enum lineType_e type,
616     struct singleLine * line) {
617        dbgPrintf("getLineByType(%d): ", type);
618        for (; line; line = line->next) {
619     dbgPrintf("%d:%s ", line->type,
620      line->numElements ? line->elements[0].item : "(empty)");
621     if (line->type & type) break;
622        }
623        dbgPrintf(line ? "\n" : " (failed)\n");
624        return line;
625    }
626    
627  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
628      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
629          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
630          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
631              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 637  static int isBracketedTitle(struct singl
637      return 0;      return 0;
638  }  }
639    
640  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
641                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
642      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
643   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;  
644  }  }
645    
646  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 691  static void lineInit(struct singleLine *
691      line->next = NULL;      line->next = NULL;
692  }  }
693    
694    struct singleLine * lineDup(struct singleLine * line) {
695        int i;
696        struct singleLine * newLine = malloc(sizeof(*newLine));
697    
698        newLine->indent = strdup(line->indent);
699        newLine->next = NULL;
700        newLine->type = line->type;
701        newLine->numElements = line->numElements;
702        newLine->elements = malloc(sizeof(*newLine->elements) *
703           newLine->numElements);
704    
705        for (i = 0; i < newLine->numElements; i++) {
706     newLine->elements[i].indent = strdup(line->elements[i].indent);
707     newLine->elements[i].item = strdup(line->elements[i].item);
708        }
709    
710        return newLine;
711    }
712    
713  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
714      int i;      int i;
715    
# Line 414  static int lineWrite(FILE * out, struct Line 735  static int lineWrite(FILE * out, struct
735      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
736    
737   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
738   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
739        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
740      }      }
741    
742      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 755  static int getNextLine(char ** bufPtr, s
755      char * chptr;      char * chptr;
756      int elementsAlloced = 0;      int elementsAlloced = 0;
757      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
758      int first = 1;      int first = 1;
     int i;  
759    
760      lineFree(line);      lineFree(line);
761    
# Line 489  static int getNextLine(char ** bufPtr, s Line 809  static int getNextLine(char ** bufPtr, s
809      if (!line->numElements)      if (!line->numElements)
810   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
811      else {      else {
812   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
813      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;  
               
814              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
815               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
816              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 846  static int getNextLine(char ** bufPtr, s
846   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
847   line->numElements = 0;   line->numElements = 0;
848      }      }
849     } else {
850     struct keywordTypes *kw;
851    
852     kw = getKeywordByType(line->type, cfi);
853    
854     /* space isn't the only separator, we need to split
855     * elements up more
856     */
857     if (!isspace(kw->separatorChar)) {
858        int i;
859        char indent[2] = "";
860        indent[0] = kw->separatorChar;
861        for (i = 1; i < line->numElements; i++) {
862     char *p;
863     int j;
864     int numNewElements;
865    
866     numNewElements = 0;
867     p = line->elements[i].item;
868     while (*p != '\0') {
869     if (*p == kw->separatorChar)
870     numNewElements++;
871     p++;
872     }
873     if (line->numElements + numNewElements >= elementsAlloced) {
874     elementsAlloced += numNewElements + 5;
875     line->elements = realloc(line->elements,
876        sizeof(*line->elements) * elementsAlloced);
877     }
878    
879     for (j = line->numElements; j > i; j--) {
880     line->elements[j + numNewElements] = line->elements[j];
881     }
882     line->numElements += numNewElements;
883    
884     p = line->elements[i].item;
885     while (*p != '\0') {
886    
887     while (*p != kw->separatorChar && *p != '\0') p++;
888     if (*p == '\0') {
889     break;
890     }
891    
892     free(line->elements[i].indent);
893     line->elements[i].indent = strdup(indent);
894     *p++ = '\0';
895     i++;
896     line->elements[i].item = strdup(p);
897     line->elements[i].indent = strdup("");
898     p = line->elements[i].item;
899     }
900        }
901     }
902   }   }
903      }      }
904    
# Line 595  static struct grubConfig * readConfig(co Line 962  static struct grubConfig * readConfig(co
962      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
963   }   }
964    
965   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
966      sawEntry = 1;      sawEntry = 1;
967      if (!entry) {      if (!entry) {
968   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 978  static struct grubConfig * readConfig(co
978      entry->next = NULL;      entry->next = NULL;
979   }   }
980    
981   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
982        int i;
983        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
984        dbgPrintf("%s", line->indent);
985        for (i = 0; i < line->numElements; i++)
986     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
987        dbgPrintf("\n");
988        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
989        if (kwType && line->numElements == 3 &&
990        !strcmp(line->elements[1].item, kwType->key)) {
991     dbgPrintf("Line sets default config\n");
992     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
993     defaultLine = line;
994        }
995     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
996      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
997      defaultLine = line;      defaultLine = line;
998    
999            } else if (line->type == LT_KERNEL) {
1000        /* if by some freak chance this is multiboot and the "module"
1001         * lines came earlier in the template, make sure to use LT_HYPER
1002         * instead of LT_KERNEL now
1003         */
1004        if (entry->multiboot)
1005     line->type = LT_HYPER;
1006    
1007          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1008        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1009         * instead, now that we know this is a multiboot entry.
1010         * This only applies to grub, but that's the only place we
1011         * should find LT_MBMODULE lines anyway.
1012         */
1013        struct singleLine * l;
1014        for (l = entry->lines; l; l = l->next) {
1015     if (l->type == LT_HYPER)
1016        break;
1017     else if (l->type == LT_KERNEL) {
1018        l->type = LT_HYPER;
1019        break;
1020     }
1021        }
1022              entry->multiboot = 1;              entry->multiboot = 1;
1023    
1024     } else if (line->type == LT_HYPER) {
1025        entry->multiboot = 1;
1026    
1027   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1028      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1029      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1030    
1031   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1032      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1033      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 1052  static struct grubConfig * readConfig(co
1052      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1053      line->elements[1].item = buf;      line->elements[1].item = buf;
1054      line->numElements = 2;      line->numElements = 2;
1055    
1056   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1057      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1058         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 652  static struct grubConfig * readConfig(co Line 1062  static struct grubConfig * readConfig(co
1062   int last, len;   int last, len;
1063    
1064   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
1065      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1066     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1067    
1068   last = line->numElements - 1;   last = line->numElements - 1;
1069   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1070   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
1071      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1072      }      }
   
1073   }   }
1074    
1075   /* 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 1089  static struct grubConfig * readConfig(co
1089   movedLine = 1;   movedLine = 1;
1090   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1091   }   }
1092    
1093   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1094     which was moved, drop it. */     which was moved, drop it. */
1095   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 1105  static struct grubConfig * readConfig(co
1105   entry->lines = line;   entry->lines = line;
1106      else      else
1107   last->next = line;   last->next = line;
1108        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1109    
1110        /* we could have seen this outside of an entry... if so, we
1111         * ignore it like any other line we don't grok */
1112        if (line->type == LT_ENTRY_END && sawEntry)
1113     sawEntry = 0;
1114   } else {   } else {
1115      if (!cfg->theLines)      if (!cfg->theLines)
1116   cfg->theLines = line;   cfg->theLines = line;
1117      else {      else
1118   last->next = line;   last->next = line;
1119      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1120   }   }
1121    
1122   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1124  static struct grubConfig * readConfig(co
1124    
1125      free(incoming);      free(incoming);
1126    
1127        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1128      if (defaultLine) {      if (defaultLine) {
1129   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1130        cfi->defaultSupportSaved &&
1131        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1132        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1133     } else if (cfi->defaultIsVariable) {
1134        char *value = defaultLine->elements[2].item;
1135        while (*value && (*value == '"' || *value == '\'' ||
1136        *value == ' ' || *value == '\t'))
1137     value++;
1138        cfg->defaultImage = strtol(value, &end, 10);
1139        while (*end && (*end == '"' || *end == '\'' ||
1140        *end == ' ' || *end == '\t'))
1141     end++;
1142        if (*end) cfg->defaultImage = -1;
1143     } else if (cfi->defaultSupportSaved &&
1144   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1145      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1146   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1161  static struct grubConfig * readConfig(co
1161                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1162                  }                  }
1163   i++;   i++;
1164     entry = NULL;
1165      }      }
1166    
1167      if (entry) cfg->defaultImage = i;      if (entry){
1168            cfg->defaultImage = i;
1169        }else{
1170            cfg->defaultImage = -1;
1171        }
1172   }   }
1173        } else {
1174            cfg->defaultImage = 0;
1175      }      }
1176    
1177      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1187  static void writeDefault(FILE * out, cha
1187    
1188      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1189   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1190        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1191     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1192      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1193   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1194      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1195      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1196     cfg->defaultImage);
1197        } else {
1198     fprintf(out, "%sdefault%s%d\n", indent, separator,
1199     cfg->defaultImage);
1200        }
1201   } else {   } else {
1202      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1203    
# Line 769  static void writeDefault(FILE * out, cha Line 1214  static void writeDefault(FILE * out, cha
1214    
1215      if (!entry) return;      if (!entry) return;
1216    
1217      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1218    
1219      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1220   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1248  static int writeConfig(struct grubConfig
1248      int rc;      int rc;
1249    
1250      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1251         directory to / */         directory to the dir of the symlink */
1252      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1253      do {      do {
1254   buf = alloca(len + 1);   buf = alloca(len + 1);
1255   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1256   if (rc == len) len += 256;   if (rc == len) len += 256;
1257      } while (rc == len);      } while (rc == len);
1258            
# Line 843  static int writeConfig(struct grubConfig Line 1287  static int writeConfig(struct grubConfig
1287      }      }
1288    
1289      line = cfg->theLines;      line = cfg->theLines;
1290        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1291      while (line) {      while (line) {
1292   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1293     line->numElements == 3 &&
1294     !strcmp(line->elements[1].item, defaultKw->key)) {
1295        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1296        needs &= ~MAIN_DEFAULT;
1297     } else if (line->type == LT_DEFAULT) {
1298      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1299      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1300   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1362  static int numEntries(struct grubConfig
1362      return i;      return i;
1363  }  }
1364    
1365    static char *findDiskForRoot()
1366    {
1367        int fd;
1368        char buf[65536];
1369        char *devname;
1370        char *chptr;
1371        int rc;
1372    
1373        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1374            fprintf(stderr, "grubby: failed to open %s: %s\n",
1375                    _PATH_MOUNTED, strerror(errno));
1376            return NULL;
1377        }
1378    
1379        rc = read(fd, buf, sizeof(buf) - 1);
1380        if (rc <= 0) {
1381            fprintf(stderr, "grubby: failed to read %s: %s\n",
1382                    _PATH_MOUNTED, strerror(errno));
1383            close(fd);
1384            return NULL;
1385        }
1386        close(fd);
1387        buf[rc] = '\0';
1388        chptr = buf;
1389    
1390        while (chptr && chptr != buf+rc) {
1391            devname = chptr;
1392    
1393            /*
1394             * The first column of a mtab entry is the device, but if the entry is a
1395             * special device it won't start with /, so move on to the next line.
1396             */
1397            if (*devname != '/') {
1398                chptr = strchr(chptr, '\n');
1399                if (chptr)
1400                    chptr++;
1401                continue;
1402            }
1403    
1404            /* Seek to the next space */
1405            chptr = strchr(chptr, ' ');
1406            if (!chptr) {
1407                fprintf(stderr, "grubby: error parsing %s: %s\n",
1408                        _PATH_MOUNTED, strerror(errno));
1409                return NULL;
1410            }
1411    
1412            /*
1413             * The second column of a mtab entry is the mount point, we are looking
1414             * for '/' obviously.
1415             */
1416            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1417                /*
1418                 * Move back 2, which is the first space after the device name, set
1419                 * it to \0 so strdup will just get the devicename.
1420                 */
1421                chptr -= 2;
1422                *chptr = '\0';
1423                return strdup(devname);
1424            }
1425    
1426            /* Next line */
1427            chptr = strchr(chptr, '\n');
1428            if (chptr)
1429                chptr++;
1430        }
1431    
1432        return NULL;
1433    }
1434    
1435    void printEntry(struct singleEntry * entry) {
1436        int i;
1437        struct singleLine * line;
1438    
1439        for (line = entry->lines; line; line = line->next) {
1440     fprintf(stderr, "DBG: %s", line->indent);
1441     for (i = 0; i < line->numElements; i++) {
1442     fprintf(stderr, "%s%s",
1443        line->elements[i].item, line->elements[i].indent);
1444     }
1445     fprintf(stderr, "\n");
1446        }
1447    }
1448    
1449    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1450    {
1451        va_list argp;
1452    
1453        if (!debug)
1454     return;
1455    
1456        va_start(argp, fmt);
1457        fprintf(stderr, "DBG: Image entry failed: ");
1458        vfprintf(stderr, fmt, argp);
1459        printEntry(entry);
1460        va_end(argp);
1461    }
1462    
1463    #define beginswith(s, c) ((s) && (s)[0] == (c))
1464    
1465    static int endswith(const char *s, char c)
1466    {
1467     int slen;
1468    
1469     if (!s || !s[0])
1470     return 0;
1471     slen = strlen(s) - 1;
1472    
1473     return s[slen] == c;
1474    }
1475    
1476  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1477    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1478      struct singleLine * line;      struct singleLine * line;
1479      char * fullName;      char * fullName;
1480      int i;      int i;
     struct stat sb, sb2;  
1481      char * dev;      char * dev;
     char * end;  
1482      char * rootspec;      char * rootspec;
1483        char * rootdev;
1484    
1485      line = entry->lines;      if (skipRemoved && entry->skip) {
1486      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1487         return 0;
1488      if (!line) return 0;      }
1489      if (skipRemoved && entry->skip) return 0;  
1490      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1491        if (!line) {
1492     notSuitablePrintf(entry, "no line found\n");
1493     return 0;
1494        }
1495        if (line->numElements < 2) {
1496     notSuitablePrintf(entry, "line has only %d elements\n",
1497        line->numElements);
1498     return 0;
1499        }
1500    
1501      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1502    
1503      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1504        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1505      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1506      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1507              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1508                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1509      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1510                line->elements[1].item + rootspec_offset);
1511        if (access(fullName, R_OK)) {
1512     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1513     return 0;
1514        }
1515      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1516   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1517      if (i < line->numElements) {      if (i < line->numElements) {
1518   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1519      } else {      } else {
1520   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1521   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1522    
1523   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1524      dev = line->elements[1].item;      dev = line->elements[1].item;
1525   } else {   } else {
1526              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1527      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */       * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1528      line = entry->lines;       */
1529        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1530    
1531              /* failed to find one */              /* failed to find one */
1532              if (!line) return 0;              if (!line) {
1533     notSuitablePrintf(entry, "no line found\n");
1534     return 0;
1535                }
1536    
1537      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1538          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1539      if (i < line->numElements)      if (i < line->numElements)
1540          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1541      else {      else {
1542     notSuitablePrintf(entry, "no root= entry found\n");
1543   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1544          return 0;          return 0;
1545              }              }
1546   }   }
1547      }      }
1548    
1549      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1550   dev += 6;      if (!getpathbyspec(dev)) {
1551            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1552   /* check which device has this label */          return 0;
1553   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1554   if (!dev) return 0;   dev = getpathbyspec(dev);
1555    
1556        rootdev = findDiskForRoot();
1557        if (!rootdev) {
1558            notSuitablePrintf(entry, "can't find root device\n");
1559     return 0;
1560      }      }
1561    
1562      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1563   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1564      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1565      } else {          free(rootdev);
1566   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1567   if (*end) return 0;      }
1568    
1569        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1570            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1571     getuuidbydev(rootdev), getuuidbydev(dev));
1572     free(rootdev);
1573            return 0;
1574      }      }
     stat("/", &sb2);  
1575    
1576      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1577    
1578      return 1;      return 1;
1579  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1617  struct singleEntry * findEntryByPath(str
1617   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1618   if (!entry) return NULL;   if (!entry) return NULL;
1619    
1620   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1621   if (!line) return NULL;   if (!line) return NULL;
1622    
1623   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1659  struct singleEntry * findEntryByPath(str
1659      kernel += 6;      kernel += 6;
1660   }   }
1661    
1662   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1663      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1664    
1665        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1666    
1667      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1668                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1669          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1670                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1671                              kernel + strlen(prefix)))       checkType, line);
1672                      break;   if (!line) break;  /* not found in this entry */
1673              }  
1674                 if (line && line->numElements >= 2) {
1675              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1676              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1677                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1678                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1679                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1680                      if (!strcmp(line->elements[1].item  +   }
1681                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1682    
1683      i++;      /* make sure this entry has a kernel identifier; this skips
1684         * non-Linux boot entries (could find netbsd etc, though, which is
1685         * unfortunate)
1686         */
1687        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1688     break; /* found 'im! */
1689   }   }
1690    
1691   if (index) *index = i;   if (index) *index = i;
1692      }      }
1693    
     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);  
     }  
   
1694      return entry;      return entry;
1695  }  }
1696    
# Line 1227  void setDefaultImage(struct grubConfig * Line 1796  void setDefaultImage(struct grubConfig *
1796    
1797      /* 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
1798         changes */         changes */
1799      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1800     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1801        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1802        return;        return;
1803    
# Line 1286  void displayEntry(struct singleEntry * e Line 1856  void displayEntry(struct singleEntry * e
1856      char * root = NULL;      char * root = NULL;
1857      int i;      int i;
1858    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1859      printf("index=%d\n", index);      printf("index=%d\n", index);
1860    
1861      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1862        if (!line) {
1863            printf("non linux entry\n");
1864            return;
1865        }
1866    
1867        printf("kernel=%s%s\n", prefix, line->elements[1].item);
1868    
1869      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1870   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1881  void displayEntry(struct singleEntry * e
1881   }   }
1882   printf("\"\n");   printf("\"\n");
1883      } else {      } else {
1884   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1885   if (line) {   if (line) {
1886      char * s;      char * s;
1887    
# Line 1334  void displayEntry(struct singleEntry * e Line 1905  void displayEntry(struct singleEntry * e
1905      }      }
1906    
1907      if (!root) {      if (!root) {
1908   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1909   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1910      root=line->elements[1].item;      root=line->elements[1].item;
1911      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1920  void displayEntry(struct singleEntry * e
1920   printf("root=%s\n", s);   printf("root=%s\n", s);
1921      }      }
1922    
1923      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1924    
1925      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1926   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1360  void displayEntry(struct singleEntry * e Line 1928  void displayEntry(struct singleEntry * e
1928      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
1929   printf("\n");   printf("\n");
1930      }      }
1931    
1932        line = getLineByType(LT_TITLE, entry->lines);
1933        if (line) {
1934     printf("title=%s\n", line->elements[1].item);
1935        } else {
1936     char * title;
1937     line = getLineByType(LT_MENUENTRY, entry->lines);
1938     title = grub2ExtractTitle(line);
1939     if (title)
1940        printf("title=%s\n", title);
1941        }
1942  }  }
1943    
1944  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1948  int parseSysconfigGrub(int * lbaPtr, cha
1948      char * start;      char * start;
1949      char * param;      char * param;
1950    
1951      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1952      if (!in) return 1;      if (!in) return 1;
1953    
1954      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 2010  int displayInfo(struct grubConfig * conf
2010   return 1;   return 1;
2011      }      }
2012    
2013      /* 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
2014         be a better way */         be a better way */
2015      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2016   dumpSysconfigGrub();   dumpSysconfigGrub();
2017      } else {      } else {
2018   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2019   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2020      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2021   }   }
2022    
2023   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2024   if (line) printf("lba\n");   if (line) printf("lba\n");
2025      }      }
2026    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2035  int displayInfo(struct grubConfig * conf
2035      return 0;      return 0;
2036  }  }
2037    
2038    struct singleLine * addLineTmpl(struct singleEntry * entry,
2039     struct singleLine * tmplLine,
2040     struct singleLine * prevLine,
2041     const char * val,
2042     struct configFileInfo * cfi)
2043    {
2044        struct singleLine * newLine = lineDup(tmplLine);
2045    
2046        if (val) {
2047     /* override the inherited value with our own.
2048     * This is a little weak because it only applies to elements[1]
2049     */
2050     if (newLine->numElements > 1)
2051        removeElement(newLine, 1);
2052     insertElement(newLine, val, 1, cfi);
2053    
2054     /* but try to keep the rootspec from the template... sigh */
2055     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2056        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2057        if (rootspec != NULL) {
2058     free(newLine->elements[1].item);
2059     newLine->elements[1].item =
2060        sdupprintf("%s%s", rootspec, val);
2061        }
2062     }
2063        }
2064    
2065        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2066          newLine->elements[0].item : "");
2067    
2068        if (!entry->lines) {
2069     /* first one on the list */
2070     entry->lines = newLine;
2071        } else if (prevLine) {
2072     /* add after prevLine */
2073     newLine->next = prevLine->next;
2074     prevLine->next = newLine;
2075        }
2076    
2077        return newLine;
2078    }
2079    
2080  /* val may be NULL */  /* val may be NULL */
2081  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2082       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2083       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2084       char * val) {       const char * val) {
2085      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2086      int i;      struct keywordTypes * kw;
2087        struct singleLine tmpl;
2088    
2089      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2090   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2091      if (type != LT_TITLE || !cfi->titleBracketed)       */
2092          if (!cfi->keywords[i].key) abort();  
2093        if (type == LT_TITLE && cfi->titleBracketed) {
2094     /* we're doing a bracketed title (zipl) */
2095     tmpl.type = type;
2096     tmpl.numElements = 1;
2097     tmpl.elements = alloca(sizeof(*tmpl.elements));
2098     tmpl.elements[0].item = alloca(strlen(val)+3);
2099     sprintf(tmpl.elements[0].item, "[%s]", val);
2100     tmpl.elements[0].indent = "";
2101     val = NULL;
2102        } else if (type == LT_MENUENTRY) {
2103     char *lineend = "--class gnu-linux --class gnu --class os {";
2104     if (!val) {
2105        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2106        abort();
2107     }
2108     kw = getKeywordByType(type, cfi);
2109     if (!kw) {
2110        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2111        abort();
2112     }
2113     tmpl.indent = "";
2114     tmpl.type = type;
2115     tmpl.numElements = 3;
2116     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2117     tmpl.elements[0].item = kw->key;
2118     tmpl.elements[0].indent = alloca(2);
2119     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2120     tmpl.elements[1].item = (char *)val;
2121     tmpl.elements[1].indent = alloca(2);
2122     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2123     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2124     strcpy(tmpl.elements[2].item, lineend);
2125     tmpl.elements[2].indent = "";
2126        } else {
2127     kw = getKeywordByType(type, cfi);
2128     if (!kw) {
2129        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2130        abort();
2131     }
2132     tmpl.type = type;
2133     tmpl.numElements = val ? 2 : 1;
2134     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2135     tmpl.elements[0].item = kw->key;
2136     tmpl.elements[0].indent = alloca(2);
2137     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2138     if (val) {
2139        tmpl.elements[1].item = (char *)val;
2140        tmpl.elements[1].indent = "";
2141     }
2142        }
2143    
2144      /* 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
2145         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2146         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
2147         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2148         differently from the rest) */         differently from the rest) */
2149      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2150   line = entry->lines;   if (line->numElements) prev = line;
2151   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2152   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;  
2153      }      }
2154    
2155      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2156          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2157          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2158          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2159          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2160          line->elements[0].indent = malloc(2);   else
2161          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2162          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2163             if (menuEntry)
2164          if (val) {      tmpl.indent = "\t";
2165              line->elements[1].item = val;   else if (prev == entry->lines)
2166              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2167          }   else
2168      } 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("");  
2169      }      }
2170    
2171      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2172  }  }
2173    
2174  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2193  void removeLine(struct singleEntry * ent
2193      free(line);      free(line);
2194  }  }
2195    
2196    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2197    {
2198        struct singleLine newLine = {
2199     .indent = tmplLine->indent,
2200     .type = tmplLine->type,
2201     .next = tmplLine->next,
2202        };
2203        int firstQuotedItem = -1;
2204        int quoteLen = 0;
2205        int j;
2206        int element = 0;
2207        char *c;
2208    
2209        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2210        strcpy(c, tmplLine->elements[0].item);
2211        insertElement(&newLine, c, element++, cfi);
2212        free(c);
2213        c = NULL;
2214    
2215        for (j = 1; j < tmplLine->numElements; j++) {
2216     if (firstQuotedItem == -1) {
2217        quoteLen += strlen(tmplLine->elements[j].item);
2218        
2219        if (isquote(tmplLine->elements[j].item[0])) {
2220     firstQuotedItem = j;
2221            quoteLen += strlen(tmplLine->elements[j].indent);
2222        } else {
2223     c = malloc(quoteLen + 1);
2224     strcpy(c, tmplLine->elements[j].item);
2225     insertElement(&newLine, c, element++, cfi);
2226     free(c);
2227     quoteLen = 0;
2228        }
2229     } else {
2230        int itemlen = strlen(tmplLine->elements[j].item);
2231        quoteLen += itemlen;
2232        quoteLen += strlen(tmplLine->elements[j].indent);
2233        
2234        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2235     c = malloc(quoteLen + 1);
2236     c[0] = '\0';
2237     for (int i = firstQuotedItem; i < j+1; i++) {
2238        strcat(c, tmplLine->elements[i].item);
2239        strcat(c, tmplLine->elements[i].indent);
2240     }
2241     insertElement(&newLine, c, element++, cfi);
2242     free(c);
2243    
2244     firstQuotedItem = -1;
2245     quoteLen = 0;
2246        }
2247     }
2248        }
2249        while (tmplLine->numElements)
2250     removeElement(tmplLine, 0);
2251        if (tmplLine->elements)
2252     free(tmplLine->elements);
2253    
2254        tmplLine->numElements = newLine.numElements;
2255        tmplLine->elements = newLine.elements;
2256    }
2257    
2258    static void insertElement(struct singleLine * line,
2259      const char * item, int insertHere,
2260      struct configFileInfo * cfi)
2261    {
2262        struct keywordTypes * kw;
2263        char indent[2] = "";
2264    
2265        /* sanity check */
2266        if (insertHere > line->numElements) {
2267     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2268      insertHere, line->numElements);
2269     insertHere = line->numElements;
2270        }
2271    
2272        line->elements = realloc(line->elements, (line->numElements + 1) *
2273         sizeof(*line->elements));
2274        memmove(&line->elements[insertHere+1],
2275        &line->elements[insertHere],
2276        (line->numElements - insertHere) *
2277        sizeof(*line->elements));
2278        line->elements[insertHere].item = strdup(item);
2279    
2280        kw = getKeywordByType(line->type, cfi);
2281    
2282        if (line->numElements == 0) {
2283     indent[0] = '\0';
2284        } else if (insertHere == 0) {
2285     indent[0] = kw->nextChar;
2286        } else if (kw->separatorChar != '\0') {
2287     indent[0] = kw->separatorChar;
2288        } else {
2289     indent[0] = ' ';
2290        }
2291    
2292        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2293     /* move the end-of-line forward */
2294     line->elements[insertHere].indent =
2295        line->elements[insertHere-1].indent;
2296     line->elements[insertHere-1].indent = strdup(indent);
2297        } else {
2298     line->elements[insertHere].indent = strdup(indent);
2299        }
2300    
2301        line->numElements++;
2302    
2303        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2304          line->elements[0].item,
2305          line->elements[insertHere].item,
2306          line->elements[insertHere].indent,
2307          insertHere);
2308    }
2309    
2310    static void removeElement(struct singleLine * line, int removeHere) {
2311        int i;
2312    
2313        /* sanity check */
2314        if (removeHere >= line->numElements) return;
2315    
2316        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2317          removeHere, line->elements[removeHere].item);
2318    
2319        free(line->elements[removeHere].item);
2320    
2321        if (removeHere > 1) {
2322     /* previous argument gets this argument's post-indentation */
2323     free(line->elements[removeHere-1].indent);
2324     line->elements[removeHere-1].indent =
2325        line->elements[removeHere].indent;
2326        } else {
2327     free(line->elements[removeHere].indent);
2328        }
2329    
2330        /* now collapse the array, but don't bother to realloc smaller */
2331        for (i = removeHere; i < line->numElements - 1; i++)
2332     line->elements[i] = line->elements[i + 1];
2333    
2334        line->numElements--;
2335    }
2336    
2337  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2338      char * first, * second;      char * first, * second;
2339      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2356  int updateActualImage(struct grubConfig
2356      struct singleEntry * entry;      struct singleEntry * entry;
2357      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2358      int index = 0;      int index = 0;
2359      int i, j, k;      int i, k;
2360      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2361      const char ** arg;      const char ** arg;
2362      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2363      int firstElement;      int firstElement;
2364      int *usedElements, *usedArgs;      int *usedElements;
2365        int doreplace;
2366    
2367      if (!image) return 0;      if (!image) return 0;
2368    
# Line 1609  int updateActualImage(struct grubConfig Line 2389  int updateActualImage(struct grubConfig
2389   }   }
2390      }      }
2391    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2392    
2393      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2394   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2395    
2396      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2397   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2398    
2399      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2400    
2401      k = 0;   if (multibootArgs && !entry->multiboot)
2402      for (arg = newArgs; *arg; arg++)      continue;
2403          k++;  
2404      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2405     * LT_KERNELARGS, use that.  Otherwise use
2406     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2407     */
2408     if (useKernelArgs) {
2409        line = getLineByType(LT_KERNELARGS, entry->lines);
2410        if (!line) {
2411     /* no LT_KERNELARGS, need to add it */
2412     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2413           cfg->secondaryIndent, NULL);
2414        }
2415        firstElement = 1;
2416    
2417      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2418   index++;      line = getLineByType(LT_HYPER, entry->lines);
2419        if (!line) {
2420     /* a multiboot entry without LT_HYPER? */
2421     continue;
2422        }
2423        firstElement = 2;
2424    
2425   line = entry->lines;   } else {
2426   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2427   if (!line) continue;      if (!line) {
2428   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2429     continue;
2430          if (entry->multiboot && !multibootArgs) {      }
2431              /* 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;  
2432   }   }
2433    
2434   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2435      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2436      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2437     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2438        /* this is a multiboot entry, make sure there's
2439         * -- on the args line
2440         */
2441        for (i = firstElement; i < line->numElements; i++) {
2442     if (!strcmp(line->elements[i].item, "--"))
2443        break;
2444        }
2445        if (i == line->numElements) {
2446     /* assume all existing args are kernel args,
2447     * prepend -- to make it official
2448     */
2449     insertElement(line, "--", firstElement, cfg->cfi);
2450     i = firstElement;
2451        }
2452        if (!multibootArgs) {
2453     /* kernel args start after the -- */
2454     firstElement = i + 1;
2455        }
2456     } else if (cfg->cfi->mbConcatArgs) {
2457        /* this is a non-multiboot entry, remove hyper args */
2458        for (i = firstElement; i < line->numElements; i++) {
2459     if (!strcmp(line->elements[i].item, "--"))
2460        break;
2461        }
2462        if (i < line->numElements) {
2463     /* remove args up to -- */
2464     while (strcmp(line->elements[firstElement].item, "--"))
2465        removeElement(line, firstElement);
2466     /* remove -- */
2467     removeElement(line, firstElement);
2468        }
2469   }   }
2470    
2471          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2472    
2473          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2474   for (arg = newArgs; *arg; arg++) {  
2475              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2476      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2477     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2478        !strcmp(line->elements[i].item, "--"))
2479     {
2480        /* reached the end of hyper args, insert here */
2481        doreplace = 0;
2482        break;  
2483     }
2484                  if (usedElements[i])                  if (usedElements[i])
2485                      continue;                      continue;
2486   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2487                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2488      break;      break;
2489                  }                  }
2490              }              }
     chptr = strchr(*arg, '=');  
2491    
2492      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2493   /* replace */   /* direct replacement */
2494   free(line->elements[i].item);   free(line->elements[i].item);
2495   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("");  
  }  
2496    
2497   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2498   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2499      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2500   /* append */   if (rootLine) {
2501   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2502   (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(" ");  
2503   } else {   } else {
2504      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2505         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2506   }   }
2507        }
2508    
2509   line->numElements++;      else {
2510     /* insert/append */
2511     insertElement(line, *arg, i, cfg->cfi);
2512     usedElements = realloc(usedElements, line->numElements *
2513           sizeof(*usedElements));
2514     memmove(&usedElements[i + 1], &usedElements[i],
2515     line->numElements - i - 1);
2516     usedElements[i] = 1;
2517    
2518   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2519     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2520     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2521   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2522      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2523      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2524   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2525   }   }
2526      }      }
             k++;  
2527   }   }
2528    
2529          free(usedElements);          free(usedElements);
2530    
  /* 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? */  
2531   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2532      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2533   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2534        !strcmp(line->elements[i].item, "--"))
2535        /* reached the end of hyper args, stop here */
2536        break;
2537     if (!argMatch(line->elements[i].item, *arg)) {
2538        removeElement(line, i);
2539      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;  
2540   }   }
2541        }
2542   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2543        if (useRoot && !strncmp(*arg, "root=", 5)) {
2544   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2545      line->elements[j - 1] = line->elements[j];   if (rootLine)
2546        removeLine(entry, rootLine);
  line->numElements--;  
2547      }      }
2548   }   }
2549    
# Line 1760  int updateActualImage(struct grubConfig Line 2554  int updateActualImage(struct grubConfig
2554   }   }
2555      }      }
2556    
     free(usedArgs);  
2557      free(newArgs);      free(newArgs);
2558      free(oldArgs);      free(oldArgs);
2559    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2579  int updateImage(struct grubConfig * cfg,
2579      return rc;      return rc;
2580  }  }
2581    
2582    int updateInitrd(struct grubConfig * cfg, const char * image,
2583                     const char * prefix, const char * initrd) {
2584        struct singleEntry * entry;
2585        struct singleLine * line, * kernelLine, *endLine = NULL;
2586        int index = 0;
2587    
2588        if (!image) return 0;
2589    
2590        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2591            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2592            if (!kernelLine) continue;
2593    
2594            line = getLineByType(LT_INITRD, entry->lines);
2595            if (line)
2596                removeLine(entry, line);
2597            if (prefix) {
2598                int prefixLen = strlen(prefix);
2599                if (!strncmp(initrd, prefix, prefixLen))
2600                    initrd += prefixLen;
2601            }
2602     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2603     if (endLine)
2604        removeLine(entry, endLine);
2605            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2606            if (!line)
2607        return 1;
2608     if (endLine) {
2609        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2610                if (!line)
2611     return 1;
2612     }
2613    
2614            break;
2615        }
2616    
2617        return 0;
2618    }
2619    
2620  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2621      int fd;      int fd;
2622      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2640  int checkDeviceBootloader(const char * d
2640      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2641   return 0;   return 0;
2642    
2643      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2644   offset = boot[2] + 2;   offset = boot[2] + 2;
2645      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2646   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2647      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2648   offset = boot[1] + 2;        offset = boot[1] + 2;
2649            /*
2650     * it looks like grub, when copying stage1 into the mbr, patches stage1
2651     * right after the JMP location, replacing other instructions such as
2652     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2653     * different bytes.
2654     */
2655          if ((bootSect[offset + 1] == NOOP_OPCODE)
2656      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2657     offset = offset + 3;
2658          }
2659      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2660   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2661      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2797  int checkForLilo(struct grubConfig * con
2797      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2798  }  }
2799    
2800    int checkForGrub2(struct grubConfig * config) {
2801        if (!access("/etc/grub.d/", R_OK))
2802     return 2;
2803    
2804        return 1;
2805    }
2806    
2807  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2808      int fd;      int fd;
2809      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2824  int checkForGrub(struct grubConfig * con
2824      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2825   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2826   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2827     close(fd);
2828     return 1;
2829        }
2830        close(fd);
2831    
2832        return checkDeviceBootloader(boot, bootSect);
2833    }
2834    
2835    int checkForExtLinux(struct grubConfig * config) {
2836        int fd;
2837        unsigned char bootSect[512];
2838        char * boot;
2839        char executable[] = "/boot/extlinux/extlinux";
2840    
2841        printf("entered: checkForExtLinux()\n");
2842    
2843        if (parseSysconfigGrub(NULL, &boot))
2844     return 0;
2845    
2846        /* assume grub is not installed -- not an error condition */
2847        if (!boot)
2848     return 0;
2849    
2850        fd = open(executable, O_RDONLY);
2851        if (fd < 0)
2852     /* this doesn't exist if grub hasn't been installed */
2853     return 0;
2854    
2855        if (read(fd, bootSect, 512) != 512) {
2856     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2857     executable, strerror(errno));
2858   return 1;   return 1;
2859      }      }
2860      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2873  static char * getRootSpecifier(char * st
2873      return rootspec;      return rootspec;
2874  }  }
2875    
2876    static char * getInitrdVal(struct grubConfig * config,
2877       const char * prefix, struct singleLine *tmplLine,
2878       const char * newKernelInitrd,
2879       char ** extraInitrds, int extraInitrdCount)
2880    {
2881        char *initrdVal, *end;
2882        int i;
2883        size_t totalSize;
2884        size_t prefixLen;
2885        char separatorChar;
2886    
2887        prefixLen = strlen(prefix);
2888        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2889    
2890        for (i = 0; i < extraInitrdCount; i++) {
2891     totalSize += sizeof(separatorChar);
2892     totalSize += strlen(extraInitrds[i]) - prefixLen;
2893        }
2894    
2895        initrdVal = end = malloc(totalSize);
2896    
2897        end = stpcpy (end, newKernelInitrd + prefixLen);
2898    
2899        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2900        for (i = 0; i < extraInitrdCount; i++) {
2901     const char *extraInitrd;
2902     int j;
2903    
2904     extraInitrd = extraInitrds[i] + prefixLen;
2905     /* Don't add entries that are already there */
2906     if (tmplLine != NULL) {
2907        for (j = 2; j < tmplLine->numElements; j++)
2908     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2909        break;
2910    
2911        if (j != tmplLine->numElements)
2912     continue;
2913     }
2914    
2915     *end++ = separatorChar;
2916     end = stpcpy(end, extraInitrd);
2917        }
2918    
2919        return initrdVal;
2920    }
2921    
2922  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2923           const char * prefix,           const char * prefix,
2924   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2925   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2926     char ** extraInitrds, int extraInitrdCount,
2927                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2928      struct singleEntry * new;      struct singleEntry * new;
2929      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2930      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2931      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2932    
2933      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2934    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2958  int addNewKernel(struct grubConfig * con
2958      config->entries = new;      config->entries = new;
2959    
2960      /* copy/update from the template */      /* copy/update from the template */
2961      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2962        if (newKernelInitrd)
2963     needs |= NEED_INITRD;
2964      if (newMBKernel) {      if (newMBKernel) {
2965          needs |= KERNEL_MB;          needs |= NEED_MB;
2966          new->multiboot = 1;          new->multiboot = 1;
2967      }      }
2968    
2969      if (template) {      if (template) {
2970   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2971      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2972      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2973   indent = tmplLine->indent;   {
2974        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2975    
2976      /* skip comments */      /* skip comments */
2977      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2978      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2979      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2980    
2981      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2982      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2983     if (!template->multiboot && (needs & NEED_MB)) {
2984              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2985                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2986                  struct singleLine *l;       * hypervisor at the same time.
2987                  needs &= ~ KERNEL_MB;       */
2988        if (config->cfi->mbHyperFirst) {
2989                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2990                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2991                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2992                      newMBKernel + strlen(prefix));
2993                  tmplLine = lastLine;   /* set up for adding the kernel line */
2994                  if (!new->lines) {   free(tmplLine->indent);
2995                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2996                  } else {   needs &= ~NEED_MB;
2997                      newLine->next = l;      }
2998                      newLine = l;      if (needs & NEED_KERNEL) {
2999                  }   /* use addLineTmpl to preserve line elements,
3000                  continue;   * otherwise we could just call addLine.  Unfortunately
3001              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3002                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3003                  continue; /* don't need multiboot kernel here */   * change below.
3004              }   */
3005     struct keywordTypes * mbm_kw =
3006        getKeywordByType(LT_MBMODULE, config->cfi);
3007     if (mbm_kw) {
3008        tmplLine->type = LT_MBMODULE;
3009        free(tmplLine->elements[0].item);
3010        tmplLine->elements[0].item = strdup(mbm_kw->key);
3011     }
3012     newLine = addLineTmpl(new, tmplLine, newLine,
3013          newKernelPath + strlen(prefix), config->cfi);
3014     needs &= ~NEED_KERNEL;
3015        }
3016        if (needs & NEED_MB) { /* !mbHyperFirst */
3017     newLine = addLine(new, config->cfi, LT_HYPER,
3018      config->secondaryIndent,
3019      newMBKernel + strlen(prefix));
3020     needs &= ~NEED_MB;
3021        }
3022     } else if (needs & NEED_KERNEL) {
3023        newLine = addLineTmpl(new, tmplLine, newLine,
3024      newKernelPath + strlen(prefix), config->cfi);
3025        needs &= ~NEED_KERNEL;
3026     }
3027    
3028      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3029   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3030   new->lines = newLine;   if (needs & NEED_MB) {
3031      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3032   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3033   newLine = newLine->next;      needs &= ~NEED_MB;
3034      }   }
3035    
3036        } else if (tmplLine->type == LT_MBMODULE &&
3037           tmplLine->numElements >= 2) {
3038     if (new->multiboot) {
3039        if (needs & NEED_KERNEL) {
3040     newLine = addLineTmpl(new, tmplLine, newLine,
3041          newKernelPath +
3042          strlen(prefix), config->cfi);
3043     needs &= ~NEED_KERNEL;
3044        } else if (config->cfi->mbInitRdIsModule &&
3045           (needs & NEED_INITRD)) {
3046     char *initrdVal;
3047     initrdVal = getInitrdVal(config, prefix, tmplLine,
3048     newKernelInitrd, extraInitrds,
3049     extraInitrdCount);
3050     newLine = addLineTmpl(new, tmplLine, newLine,
3051          initrdVal, config->cfi);
3052     free(initrdVal);
3053     needs &= ~NEED_INITRD;
3054        }
3055     } else if (needs & NEED_KERNEL) {
3056        /* template is multi but new is not,
3057         * insert the kernel in the first module slot
3058         */
3059        tmplLine->type = LT_KERNEL;
3060        free(tmplLine->elements[0].item);
3061        tmplLine->elements[0].item =
3062     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3063        newLine = addLineTmpl(new, tmplLine, newLine,
3064      newKernelPath + strlen(prefix), config->cfi);
3065        needs &= ~NEED_KERNEL;
3066     } else if (needs & NEED_INITRD) {
3067        char *initrdVal;
3068        /* template is multi but new is not,
3069         * insert the initrd in the second module slot
3070         */
3071        tmplLine->type = LT_INITRD;
3072        free(tmplLine->elements[0].item);
3073        tmplLine->elements[0].item =
3074     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3075        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3076        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3077        free(initrdVal);
3078        needs &= ~NEED_INITRD;
3079     }
3080    
     newLine->indent = strdup(tmplLine->indent);  
     newLine->next = NULL;  
     newLine->type = tmplLine->type;  
     newLine->numElements = tmplLine->numElements;  
     newLine->elements = malloc(sizeof(*newLine->elements) *  
     newLine->numElements);  
     for (i = 0; i < newLine->numElements; i++) {  
  newLine->elements[i].item = strdup(tmplLine->elements[i].item);  
  newLine->elements[i].indent =  
  strdup(tmplLine->elements[i].indent);  
     }  
   
             lastLine = tmplLine;  
     if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {  
                 char * repl;  
                 if (!template->multiboot) {  
                     needs &= ~KERNEL_KERNEL;  
                     repl = newKernelPath;  
                 } else {  
                     needs &= ~KERNEL_MB;  
                     repl = newMBKernel;  
                 }  
                 if (new->multiboot && !template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("module");  
                     newLine->type = LT_MBMODULE;  
                 }  
  free(newLine->elements[1].item);  
                 rootspec = getRootSpecifier(tmplLine->elements[1].item);  
                 if (rootspec != NULL) {  
                     newLine->elements[1].item = sdupprintf("%s%s",  
                                                            rootspec,  
                                                            repl +  
                                                            strlen(prefix));  
                 } else {  
                     newLine->elements[1].item = strdup(repl +  
                                                        strlen(prefix));  
                 }  
             } else if (tmplLine->type == LT_MBMODULE &&  
                        tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {  
                 needs &= ~KERNEL_KERNEL;  
                 if (!new->multiboot && template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("kernel");  
                     newLine->type = LT_KERNEL;  
                 }  
  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));  
                 }  
3081      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3082      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3083   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3084   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3085                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3086                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3087                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3088                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3089                  }       */
3090                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3091                  if (rootspec != NULL) {   char *initrdVal;
3092                      newLine->elements[1].item = sdupprintf("%s%s",  
3093                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3094                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3095                                                             strlen(prefix));    config->secondaryIndent,
3096                  } else {    initrdVal);
3097                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3098                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3099                  }      }
3100              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3101                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3102   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3103                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3104                      free(newLine->elements[0].item);      free(initrdVal);
3105                      newLine->elements[0].item = strdup("initrd");      needs &= ~NEED_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;  
   
  for (i = 1; i < newLine->numElements; i++) {  
     free(newLine->elements[i].item);  
     free(newLine->elements[i].indent);  
3106   }   }
3107    
3108   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3109   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3110   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3111     char *nkt = malloc(strlen(newKernelTitle)+3);
3112     strcpy(nkt, "'");
3113     strcat(nkt, newKernelTitle);
3114     strcat(nkt, "'");
3115     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3116     free(nkt);
3117     needs &= ~NEED_TITLE;
3118      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3119                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3120                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3121                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3122                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3123                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3124                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3125                                             newLine->numElements);     config->cfi->titleBracketed) {
3126        /* addLineTmpl doesn't handle titleBracketed */
3127                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3128                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3129                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3130                  newLine->numElements = 1;   }
3131              }      } else if (tmplLine->type == LT_ECHO) {
3132        requote(tmplLine, config->cfi);
3133        static const char *prefix = "'Loading ";
3134        if (tmplLine->numElements > 1 &&
3135        strstr(tmplLine->elements[1].item, prefix) &&
3136        masterLine->next && masterLine->next->type == LT_KERNEL) {
3137     char *newTitle = malloc(strlen(prefix) +
3138     strlen(newKernelTitle) + 2);
3139    
3140     strcpy(newTitle, prefix);
3141     strcat(newTitle, newKernelTitle);
3142     strcat(newTitle, "'");
3143     newLine = addLine(new, config->cfi, LT_ECHO,
3144     tmplLine->indent, newTitle);
3145     free(newTitle);
3146        } else {
3147     /* pass through other lines from the template */
3148     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3149     config->cfi);
3150        }
3151        } else {
3152     /* pass through other lines from the template */
3153     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3154        }
3155   }   }
3156    
3157      } else {      } else {
3158   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3159      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3160     */
3161     switch (config->cfi->entryStart) {
3162        case LT_KERNEL:
3163     if (new->multiboot && config->cfi->mbHyperFirst) {
3164        /* fall through to LT_HYPER */
3165     } else {
3166        newLine = addLine(new, config->cfi, LT_KERNEL,
3167          config->primaryIndent,
3168          newKernelPath + strlen(prefix));
3169        needs &= ~NEED_KERNEL;
3170        break;
3171     }
3172    
3173        case LT_HYPER:
3174     newLine = addLine(new, config->cfi, LT_HYPER,
3175      config->primaryIndent,
3176      newMBKernel + strlen(prefix));
3177     needs &= ~NEED_MB;
3178   break;   break;
         }  
3179    
3180   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3181      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3182       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3183       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3184      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3185       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3186      default:        config->primaryIndent, nkt);
3187                  /* zipl strikes again */   free(nkt);
3188                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3189                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3190                      chptr = newKernelTitle;   break;
3191                      type = LT_TITLE;      }
3192                      break;      case LT_TITLE:
3193                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3194                      abort();   char * templabel;
3195                  }   int x = 0, y = 0;
3196   }  
3197     templabel = strdup(newKernelTitle);
3198     while( templabel[x]){
3199     if( templabel[x] == ' ' ){
3200     y = x;
3201     while( templabel[y] ){
3202     templabel[y] = templabel[y+1];
3203     y++;
3204     }
3205     }
3206     x++;
3207     }
3208     newLine = addLine(new, config->cfi, LT_TITLE,
3209      config->primaryIndent, templabel);
3210     free(templabel);
3211     }else{
3212     newLine = addLine(new, config->cfi, LT_TITLE,
3213      config->primaryIndent, newKernelTitle);
3214     }
3215     needs &= ~NEED_TITLE;
3216     break;
3217    
3218   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3219   new->lines = newLine;   abort();
3220     }
3221      }      }
3222    
3223      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3224          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3225              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3226                                config->secondaryIndent,       */
3227                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3228          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3229              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3230                                config->secondaryIndent,    newKernelTitle);
3231                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3232          /* don't need to check for title as it's guaranteed to have been      }
3233           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3234           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3235          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3236              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3237                                config->secondaryIndent,   needs &= ~NEED_MB;
3238                                newKernelInitrd + strlen(prefix));      }
3239      } else {      if (needs & NEED_KERNEL) {
3240          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3241              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3242                                config->secondaryIndent,        config->cfi)) ?
3243                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3244          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3245              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3246                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3247                                newKernelTitle);      }
3248          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3249              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3250                                config->secondaryIndent,    config->secondaryIndent,
3251                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3252     needs &= ~NEED_MB;
3253        }
3254        if (needs & NEED_INITRD) {
3255     char *initrdVal;
3256     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3257     newLine = addLine(new, config->cfi,
3258      (new->multiboot && getKeywordByType(LT_MBMODULE,
3259          config->cfi)) ?
3260      LT_MBMODULE : LT_INITRD,
3261      config->secondaryIndent,
3262      initrdVal);
3263     free(initrdVal);
3264     needs &= ~NEED_INITRD;
3265        }
3266        if (needs & NEED_END) {
3267     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3268     config->secondaryIndent, NULL);
3269     needs &= ~NEED_END;
3270        }
3271    
3272        if (needs) {
3273     printf(_("grubby: needs=%d, aborting\n"), needs);
3274     abort();
3275      }      }
3276    
3277      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3280  int addNewKernel(struct grubConfig * con
3280      return 0;      return 0;
3281  }  }
3282    
3283    static void traceback(int signum)
3284    {
3285        void *array[40];
3286        size_t size;
3287    
3288        signal(SIGSEGV, SIG_DFL);
3289        memset(array, '\0', sizeof (array));
3290        size = backtrace(array, 40);
3291    
3292        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3293                (unsigned long)size);
3294        backtrace_symbols_fd(array, size, STDERR_FILENO);
3295        exit(1);
3296    }
3297    
3298  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3299      poptContext optCon;      poptContext optCon;
3300      char * grubConfig = NULL;      const char * grubConfig = NULL;
3301      char * outputFile = NULL;      char * outputFile = NULL;
3302      int arg = 0;      int arg = 0;
3303      int flags = 0;      int flags = 0;
3304      int badImageOkay = 0;      int badImageOkay = 0;
3305        int configureGrub2 = 0;
3306      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3307      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3308        int configureExtLinux = 0;
3309      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3310        int extraInitrdCount = 0;
3311      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3312      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3313      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3323  int main(int argc, const char ** argv) {
3323      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3324      char * removeArgs = NULL;      char * removeArgs = NULL;
3325      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3326        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3327      const char * chptr = NULL;      const char * chptr = NULL;
3328      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3329      struct grubConfig * config;      struct grubConfig * config;
3330      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3331      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3332      int displayDefault = 0;      int displayDefault = 0;
3333        int displayDefaultIndex = 0;
3334        int displayDefaultTitle = 0;
3335      struct poptOption options[] = {      struct poptOption options[] = {
3336   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3337      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2335  int main(int argc, const char ** argv) { Line 3362  int main(int argc, const char ** argv) {
3362        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3363        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3364        "template"), NULL },        "template"), NULL },
3365     { "debug", 0, 0, &debug, 0,
3366        _("print debugging information for failures") },
3367   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3368      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3369     { "default-index", 0, 0, &displayDefaultIndex, 0,
3370        _("display the index of the default kernel") },
3371     { "default-title", 0, 0, &displayDefaultTitle, 0,
3372        _("display the title of the default kernel") },
3373   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3374      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3375     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3376        _("configure extlinux bootloader (from syslinux)") },
3377   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3378      _("configure grub bootloader") },      _("configure grub bootloader") },
3379     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3380        _("configure grub2 bootloader") },
3381   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3382      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3383      _("kernel-path") },      _("kernel-path") },
3384   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3385      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3386     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3387        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3388   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3389      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3390   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3421  int main(int argc, const char ** argv) {
3421   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3422      };      };
3423    
3424        useextlinuxmenu=0;
3425    
3426        signal(SIGSEGV, traceback);
3427    
3428      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3429      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3430    
# Line 2391  int main(int argc, const char ** argv) { Line 3434  int main(int argc, const char ** argv) {
3434      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3435      exit(0);      exit(0);
3436      break;      break;
3437      case 'i':
3438        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3439         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3440        } else {
3441     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3442     return 1;
3443        }
3444        break;
3445   }   }
3446      }      }
3447    
# Line 2406  int main(int argc, const char ** argv) { Line 3457  int main(int argc, const char ** argv) {
3457   return 1;   return 1;
3458      }      }
3459    
3460      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3461   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3462     configureExtLinux ) > 1) {
3463   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3464   return 1;   return 1;
3465      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3466   fprintf(stderr,   fprintf(stderr,
3467      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3468   return 1;   return 1;
3469        } else if (configureGrub2) {
3470     cfi = &grub2ConfigType;
3471      } else if (configureLilo) {      } else if (configureLilo) {
3472   cfi = &liloConfigType;   cfi = &liloConfigType;
3473      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3480  int main(int argc, const char ** argv) {
3480          cfi = &siloConfigType;          cfi = &siloConfigType;
3481      } else if (configureZipl) {      } else if (configureZipl) {
3482          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3483        } else if (configureExtLinux) {
3484     cfi = &extlinuxConfigType;
3485     useextlinuxmenu=1;
3486      }      }
3487    
3488      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3497  int main(int argc, const char ** argv) {
3497        #elif __s390x__        #elif __s390x__
3498          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3499        #else        #else
3500   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3501        cfi = &grub2ConfigType;
3502     else
3503        cfi = &grubConfigType;
3504        #endif        #endif
3505      }      }
3506    
3507      if (!grubConfig)      if (!grubConfig) {
3508   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3509        grubConfig = cfi->findConfig(cfi);
3510     if (!grubConfig)
3511        grubConfig = cfi->defaultConfig;
3512        }
3513    
3514      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3515    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3516    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3517   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3518    "specified option"));    "specified option"));
3519   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3529  int main(int argc, const char ** argv) {
3529      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3530   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3531   return 1;   return 1;
3532      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3533    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3534    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3535   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3536   return 1;   return 1;
3537      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3556  int main(int argc, const char ** argv) {
3556   defaultKernel = NULL;   defaultKernel = NULL;
3557      }      }
3558    
3559      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3560   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3561   "is used\n"));   "is used\n"));
3562   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3564  int main(int argc, const char ** argv) {
3564    
3565      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3566   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3567          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3568   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3569   return 1;   return 1;
3570      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3584  int main(int argc, const char ** argv) {
3584   bootPrefix = "";   bootPrefix = "";
3585      }      }
3586    
3587        if (!cfi->mbAllowExtraInitRds &&
3588     extraInitrdCount > 0) {
3589     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3590     return 1;
3591        }
3592    
3593      if (bootloaderProbe) {      if (bootloaderProbe) {
3594   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3595   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3596    
3597   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3598      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3599        gconfig = readConfig(grub2config, &grub2ConfigType);
3600        if (!gconfig)
3601     gr2c = 1;
3602        else
3603     gr2c = checkForGrub2(gconfig);
3604     }
3605    
3606     const char *grubconfig = grubFindConfig(&grubConfigType);
3607     if (!access(grubconfig, F_OK)) {
3608        gconfig = readConfig(grubconfig, &grubConfigType);
3609      if (!gconfig)      if (!gconfig)
3610   grc = 1;   grc = 1;
3611      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3620  int main(int argc, const char ** argv) {
3620   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3621   }   }
3622    
3623   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3624        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3625        if (!lconfig)
3626     erc = 1;
3627        else
3628     erc = checkForExtLinux(lconfig);
3629     }
3630    
3631     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3632    
3633   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3634     if (gr2c == 2) printf("grub2\n");
3635   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3636     if (erc == 2) printf("extlinux\n");
3637    
3638   return 0;   return 0;
3639      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3651  int main(int argc, const char ** argv) {
3651   if (!entry) return 0;   if (!entry) return 0;
3652   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3653    
3654   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3655   if (!line) return 0;   if (!line) return 0;
3656    
3657          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3659  int main(int argc, const char ** argv) {
3659                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3660    
3661   return 0;   return 0;
3662    
3663        } else if (displayDefaultTitle) {
3664     struct singleLine * line;
3665     struct singleEntry * entry;
3666    
3667     if (config->defaultImage == -1) return 0;
3668     entry = findEntryByIndex(config, config->defaultImage);
3669     if (!entry) return 0;
3670    
3671     if (!configureGrub2) {
3672      line = getLineByType(LT_TITLE, entry->lines);
3673      if (!line) return 0;
3674      printf("%s\n", line->elements[1].item);
3675    
3676     } else {
3677      char * title;
3678    
3679      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3680      line = getLineByType(LT_MENUENTRY, entry->lines);
3681      if (!line) return 0;
3682      title = grub2ExtractTitle(line);
3683      if (title)
3684        printf("%s\n", title);
3685     }
3686     return 0;
3687    
3688        } else if (displayDefaultIndex) {
3689            if (config->defaultImage == -1) return 0;
3690            printf("%i\n", config->defaultImage);
3691    
3692      } else if (kernelInfo)      } else if (kernelInfo)
3693   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3694    
# Line 2585  int main(int argc, const char ** argv) { Line 3704  int main(int argc, const char ** argv) {
3704      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3705      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3706                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3707        if (updateKernelPath && newKernelInitrd) {
3708                if (updateInitrd(config, updateKernelPath, bootPrefix,
3709                                 newKernelInitrd)) return 1;
3710        }
3711      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3712                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3713                         extraInitrds, extraInitrdCount,
3714                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3715            
3716    
# Line 2597  int main(int argc, const char ** argv) { Line 3721  int main(int argc, const char ** argv) {
3721      }      }
3722    
3723      if (!outputFile)      if (!outputFile)
3724   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3725    
3726      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3727  }  }

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