Magellan Linux

Diff of /trunk/grubby/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 1840 by niro, Mon Jul 2 12:48:49 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 410  static int lineWrite(FILE * out, struct Line 731  static int lineWrite(FILE * out, struct
731      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
732    
733      for (i = 0; i < line->numElements; i++) {      for (i = 0; i < line->numElements; i++) {
734     /* Need to handle this, because we strip the quotes from
735     * menuentry when read it. */
736     if (line->type == LT_MENUENTRY && i == 1) {
737        if(!isquote(*line->elements[i].item))
738     fprintf(out, "\'%s\'", line->elements[i].item);
739        else
740     fprintf(out, "%s", line->elements[i].item);
741        fprintf(out, "%s", line->elements[i].indent);
742    
743        continue;
744     }
745    
746   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
747      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
748    
749   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
750   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
751        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
752      }      }
753    
754      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 767  static int getNextLine(char ** bufPtr, s
767      char * chptr;      char * chptr;
768      int elementsAlloced = 0;      int elementsAlloced = 0;
769      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
770      int first = 1;      int first = 1;
     int i;  
771    
772      lineFree(line);      lineFree(line);
773    
# Line 489  static int getNextLine(char ** bufPtr, s Line 821  static int getNextLine(char ** bufPtr, s
821      if (!line->numElements)      if (!line->numElements)
822   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
823      else {      else {
824   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
825      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;  
               
826              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
827               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
828              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 858  static int getNextLine(char ** bufPtr, s
858   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
859   line->numElements = 0;   line->numElements = 0;
860      }      }
861     } else {
862     struct keywordTypes *kw;
863    
864     kw = getKeywordByType(line->type, cfi);
865    
866     /* space isn't the only separator, we need to split
867     * elements up more
868     */
869     if (!isspace(kw->separatorChar)) {
870        int i;
871        char indent[2] = "";
872        indent[0] = kw->separatorChar;
873        for (i = 1; i < line->numElements; i++) {
874     char *p;
875     int j;
876     int numNewElements;
877    
878     numNewElements = 0;
879     p = line->elements[i].item;
880     while (*p != '\0') {
881     if (*p == kw->separatorChar)
882     numNewElements++;
883     p++;
884     }
885     if (line->numElements + numNewElements >= elementsAlloced) {
886     elementsAlloced += numNewElements + 5;
887     line->elements = realloc(line->elements,
888        sizeof(*line->elements) * elementsAlloced);
889     }
890    
891     for (j = line->numElements; j > i; j--) {
892     line->elements[j + numNewElements] = line->elements[j];
893     }
894     line->numElements += numNewElements;
895    
896     p = line->elements[i].item;
897     while (*p != '\0') {
898    
899     while (*p != kw->separatorChar && *p != '\0') p++;
900     if (*p == '\0') {
901     break;
902     }
903    
904     line->elements[i + 1].indent = line->elements[i].indent;
905     line->elements[i].indent = strdup(indent);
906     *p++ = '\0';
907     i++;
908     line->elements[i].item = strdup(p);
909     }
910        }
911     }
912   }   }
913      }      }
914    
# Line 595  static struct grubConfig * readConfig(co Line 972  static struct grubConfig * readConfig(co
972      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
973   }   }
974    
975   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
976      sawEntry = 1;      sawEntry = 1;
977      if (!entry) {      if (!entry) {
978   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 988  static struct grubConfig * readConfig(co
988      entry->next = NULL;      entry->next = NULL;
989   }   }
990    
991   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
992        int i;
993        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
994        dbgPrintf("%s", line->indent);
995        for (i = 0; i < line->numElements; i++)
996     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
997        dbgPrintf("\n");
998        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
999        if (kwType && line->numElements == 3 &&
1000        !strcmp(line->elements[1].item, kwType->key)) {
1001     dbgPrintf("Line sets default config\n");
1002     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1003     defaultLine = line;
1004        }
1005     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1006      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1007      defaultLine = line;      defaultLine = line;
1008    
1009            } else if (line->type == LT_KERNEL) {
1010        /* if by some freak chance this is multiboot and the "module"
1011         * lines came earlier in the template, make sure to use LT_HYPER
1012         * instead of LT_KERNEL now
1013         */
1014        if (entry->multiboot)
1015     line->type = LT_HYPER;
1016    
1017          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1018        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1019         * instead, now that we know this is a multiboot entry.
1020         * This only applies to grub, but that's the only place we
1021         * should find LT_MBMODULE lines anyway.
1022         */
1023        struct singleLine * l;
1024        for (l = entry->lines; l; l = l->next) {
1025     if (l->type == LT_HYPER)
1026        break;
1027     else if (l->type == LT_KERNEL) {
1028        l->type = LT_HYPER;
1029        break;
1030     }
1031        }
1032              entry->multiboot = 1;              entry->multiboot = 1;
1033    
1034     } else if (line->type == LT_HYPER) {
1035        entry->multiboot = 1;
1036    
1037   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1038      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1039      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1040    
1041   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1042      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1043      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 1062  static struct grubConfig * readConfig(co
1062      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1063      line->elements[1].item = buf;      line->elements[1].item = buf;
1064      line->numElements = 2;      line->numElements = 2;
1065     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1066        /* let --remove-kernel="TITLE=what" work */
1067        len = 0;
1068        char *extras;
1069        char *title;
1070    
1071        for (i = 1; i < line->numElements; i++) {
1072     len += strlen(line->elements[i].item);
1073     len += strlen(line->elements[i].indent);
1074        }
1075        buf = malloc(len + 1);
1076        *buf = '\0';
1077    
1078        /* allocate mem for extra flags. */
1079        extras = malloc(len + 1);
1080        *extras = '\0';
1081    
1082        /* get title. */
1083        for (i = 0; i < line->numElements; i++) {
1084     if (!strcmp(line->elements[i].item, "menuentry"))
1085        continue;
1086     if (isquote(*line->elements[i].item))
1087        title = line->elements[i].item + 1;
1088     else
1089        title = line->elements[i].item;
1090    
1091     len = strlen(title);
1092            if (isquote(title[len-1])) {
1093        strncat(buf, title,len-1);
1094        break;
1095     } else {
1096        strcat(buf, title);
1097        strcat(buf, line->elements[i].indent);
1098     }
1099        }
1100    
1101        /* get extras */
1102        int count = 0;
1103        for (i = 0; i < line->numElements; i++) {
1104     if (count >= 2) {
1105        strcat(extras, line->elements[i].item);
1106        strcat(extras, line->elements[i].indent);
1107     }
1108    
1109     if (!strcmp(line->elements[i].item, "menuentry"))
1110        continue;
1111    
1112     /* count ' or ", there should be two in menuentry line. */
1113     if (isquote(*line->elements[i].item))
1114        count++;
1115    
1116     len = strlen(line->elements[i].item);
1117    
1118     if (isquote(line->elements[i].item[len -1]))
1119        count++;
1120    
1121     /* ok, we get the final ' or ", others are extras. */
1122                }
1123        line->elements[1].indent =
1124     line->elements[line->numElements - 2].indent;
1125        line->elements[1].item = buf;
1126        line->elements[2].indent =
1127     line->elements[line->numElements - 2].indent;
1128        line->elements[2].item = extras;
1129        line->numElements = 3;
1130   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1131      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1132         on write. This is one of the few (the only?) places that grubby         on write. This is one of the few (the only?) places that grubby
# Line 651  static struct grubConfig * readConfig(co Line 1135  static struct grubConfig * readConfig(co
1135      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1136   int last, len;   int last, len;
1137    
1138   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1139      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1140     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1141    
1142   last = line->numElements - 1;   last = line->numElements - 1;
1143   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1144   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1145      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1146      }      }
   
1147   }   }
1148    
1149   /* 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 1163  static struct grubConfig * readConfig(co
1163   movedLine = 1;   movedLine = 1;
1164   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1165   }   }
1166    
1167   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1168     which was moved, drop it. */     which was moved, drop it. */
1169   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 1179  static struct grubConfig * readConfig(co
1179   entry->lines = line;   entry->lines = line;
1180      else      else
1181   last->next = line;   last->next = line;
1182        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1183    
1184        /* we could have seen this outside of an entry... if so, we
1185         * ignore it like any other line we don't grok */
1186        if (line->type == LT_ENTRY_END && sawEntry)
1187     sawEntry = 0;
1188   } else {   } else {
1189      if (!cfg->theLines)      if (!cfg->theLines)
1190   cfg->theLines = line;   cfg->theLines = line;
1191      else {      else
1192   last->next = line;   last->next = line;
1193      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1194   }   }
1195    
1196   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1198  static struct grubConfig * readConfig(co
1198    
1199      free(incoming);      free(incoming);
1200    
1201        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1202      if (defaultLine) {      if (defaultLine) {
1203   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1204        cfi->defaultSupportSaved &&
1205        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1206        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1207     } else if (cfi->defaultIsVariable) {
1208        char *value = defaultLine->elements[2].item;
1209        while (*value && (*value == '"' || *value == '\'' ||
1210        *value == ' ' || *value == '\t'))
1211     value++;
1212        cfg->defaultImage = strtol(value, &end, 10);
1213        while (*end && (*end == '"' || *end == '\'' ||
1214        *end == ' ' || *end == '\t'))
1215     end++;
1216        if (*end) cfg->defaultImage = -1;
1217     } else if (cfi->defaultSupportSaved &&
1218   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1219      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1220   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1235  static struct grubConfig * readConfig(co
1235                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1236                  }                  }
1237   i++;   i++;
1238     entry = NULL;
1239      }      }
1240    
1241      if (entry) cfg->defaultImage = i;      if (entry){
1242            cfg->defaultImage = i;
1243        }else{
1244            cfg->defaultImage = -1;
1245        }
1246   }   }
1247        } else {
1248            cfg->defaultImage = 0;
1249      }      }
1250    
1251      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1261  static void writeDefault(FILE * out, cha
1261    
1262      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1263   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1264        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1265     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1266      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1267   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1268      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1269      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1270     cfg->defaultImage);
1271        } else {
1272     fprintf(out, "%sdefault%s%d\n", indent, separator,
1273     cfg->defaultImage);
1274        }
1275   } else {   } else {
1276      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1277    
# Line 769  static void writeDefault(FILE * out, cha Line 1288  static void writeDefault(FILE * out, cha
1288    
1289      if (!entry) return;      if (!entry) return;
1290    
1291      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1292    
1293      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1294   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1322  static int writeConfig(struct grubConfig
1322      int rc;      int rc;
1323    
1324      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1325         directory to / */         directory to the dir of the symlink */
1326      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1327      do {      do {
1328   buf = alloca(len + 1);   buf = alloca(len + 1);
1329   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1330   if (rc == len) len += 256;   if (rc == len) len += 256;
1331      } while (rc == len);      } while (rc == len);
1332            
# Line 843  static int writeConfig(struct grubConfig Line 1361  static int writeConfig(struct grubConfig
1361      }      }
1362    
1363      line = cfg->theLines;      line = cfg->theLines;
1364        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1365      while (line) {      while (line) {
1366   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1367     line->numElements == 3 &&
1368     !strcmp(line->elements[1].item, defaultKw->key)) {
1369        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1370        needs &= ~MAIN_DEFAULT;
1371     } else if (line->type == LT_DEFAULT) {
1372      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1373      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1374   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1436  static int numEntries(struct grubConfig
1436      return i;      return i;
1437  }  }
1438    
1439    static char *findDiskForRoot()
1440    {
1441        int fd;
1442        char buf[65536];
1443        char *devname;
1444        char *chptr;
1445        int rc;
1446    
1447        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1448            fprintf(stderr, "grubby: failed to open %s: %s\n",
1449                    _PATH_MOUNTED, strerror(errno));
1450            return NULL;
1451        }
1452    
1453        rc = read(fd, buf, sizeof(buf) - 1);
1454        if (rc <= 0) {
1455            fprintf(stderr, "grubby: failed to read %s: %s\n",
1456                    _PATH_MOUNTED, strerror(errno));
1457            close(fd);
1458            return NULL;
1459        }
1460        close(fd);
1461        buf[rc] = '\0';
1462        chptr = buf;
1463    
1464        while (chptr && chptr != buf+rc) {
1465            devname = chptr;
1466    
1467            /*
1468             * The first column of a mtab entry is the device, but if the entry is a
1469             * special device it won't start with /, so move on to the next line.
1470             */
1471            if (*devname != '/') {
1472                chptr = strchr(chptr, '\n');
1473                if (chptr)
1474                    chptr++;
1475                continue;
1476            }
1477    
1478            /* Seek to the next space */
1479            chptr = strchr(chptr, ' ');
1480            if (!chptr) {
1481                fprintf(stderr, "grubby: error parsing %s: %s\n",
1482                        _PATH_MOUNTED, strerror(errno));
1483                return NULL;
1484            }
1485    
1486            /*
1487             * The second column of a mtab entry is the mount point, we are looking
1488             * for '/' obviously.
1489             */
1490            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1491                /*
1492                 * Move back 2, which is the first space after the device name, set
1493                 * it to \0 so strdup will just get the devicename.
1494                 */
1495                chptr -= 2;
1496                *chptr = '\0';
1497                return strdup(devname);
1498            }
1499    
1500            /* Next line */
1501            chptr = strchr(chptr, '\n');
1502            if (chptr)
1503                chptr++;
1504        }
1505    
1506        return NULL;
1507    }
1508    
1509    void printEntry(struct singleEntry * entry) {
1510        int i;
1511        struct singleLine * line;
1512    
1513        for (line = entry->lines; line; line = line->next) {
1514     fprintf(stderr, "DBG: %s", line->indent);
1515     for (i = 0; i < line->numElements; i++) {
1516        /* Need to handle this, because we strip the quotes from
1517         * menuentry when read it. */
1518        if (line->type == LT_MENUENTRY && i == 1) {
1519     if(!isquote(*line->elements[i].item))
1520        fprintf(stderr, "\'%s\'", line->elements[i].item);
1521     else
1522        fprintf(stderr, "%s", line->elements[i].item);
1523     fprintf(stderr, "%s", line->elements[i].indent);
1524    
1525     continue;
1526        }
1527        
1528        fprintf(stderr, "%s%s",
1529        line->elements[i].item, line->elements[i].indent);
1530     }
1531     fprintf(stderr, "\n");
1532        }
1533    }
1534    
1535    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1536    {
1537        va_list argp;
1538    
1539        if (!debug)
1540     return;
1541    
1542        va_start(argp, fmt);
1543        fprintf(stderr, "DBG: Image entry failed: ");
1544        vfprintf(stderr, fmt, argp);
1545        printEntry(entry);
1546        va_end(argp);
1547    }
1548    
1549    #define beginswith(s, c) ((s) && (s)[0] == (c))
1550    
1551    static int endswith(const char *s, char c)
1552    {
1553     int slen;
1554    
1555     if (!s || !s[0])
1556     return 0;
1557     slen = strlen(s) - 1;
1558    
1559     return s[slen] == c;
1560    }
1561    
1562  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1563    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1564      struct singleLine * line;      struct singleLine * line;
1565      char * fullName;      char * fullName;
1566      int i;      int i;
     struct stat sb, sb2;  
1567      char * dev;      char * dev;
     char * end;  
1568      char * rootspec;      char * rootspec;
1569        char * rootdev;
1570    
1571      line = entry->lines;      if (skipRemoved && entry->skip) {
1572      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1573         return 0;
1574      if (!line) return 0;      }
1575      if (skipRemoved && entry->skip) return 0;  
1576      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1577        if (!line) {
1578     notSuitablePrintf(entry, "no line found\n");
1579     return 0;
1580        }
1581        if (line->numElements < 2) {
1582     notSuitablePrintf(entry, "line has only %d elements\n",
1583        line->numElements);
1584     return 0;
1585        }
1586    
1587      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1588    
1589      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1590        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1591      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1592      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1593              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1594                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1595      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1596                line->elements[1].item + rootspec_offset);
1597        if (access(fullName, R_OK)) {
1598     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1599     return 0;
1600        }
1601      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1602   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1603      if (i < line->numElements) {      if (i < line->numElements) {
1604   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1605      } else {      } else {
1606   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1607   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1608    
1609   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1610      dev = line->elements[1].item;      dev = line->elements[1].item;
1611   } else {   } else {
1612              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1613      /* 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.
1614      line = entry->lines;       */
1615        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1616    
1617              /* failed to find one */              /* failed to find one */
1618              if (!line) return 0;              if (!line) {
1619     notSuitablePrintf(entry, "no line found\n");
1620     return 0;
1621                }
1622    
1623      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1624          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1625      if (i < line->numElements)      if (i < line->numElements)
1626          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1627      else {      else {
1628     notSuitablePrintf(entry, "no root= entry found\n");
1629   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1630          return 0;          return 0;
1631              }              }
1632   }   }
1633      }      }
1634    
1635      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1636   dev += 6;      if (!getpathbyspec(dev)) {
1637            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1638   /* check which device has this label */          return 0;
1639   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1640   if (!dev) return 0;   dev = getpathbyspec(dev);
1641    
1642        rootdev = findDiskForRoot();
1643        if (!rootdev) {
1644            notSuitablePrintf(entry, "can't find root device\n");
1645     return 0;
1646      }      }
1647    
1648      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1649   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1650      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1651      } else {          free(rootdev);
1652   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1653   if (*end) return 0;      }
1654    
1655        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1656            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1657     getuuidbydev(rootdev), getuuidbydev(dev));
1658     free(rootdev);
1659            return 0;
1660      }      }
     stat("/", &sb2);  
1661    
1662      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1663    
1664      return 1;      return 1;
1665  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1703  struct singleEntry * findEntryByPath(str
1703   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1704   if (!entry) return NULL;   if (!entry) return NULL;
1705    
1706   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1707   if (!line) return NULL;   if (!line) return NULL;
1708    
1709   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1741  struct singleEntry * findEntryByPath(str
1741    
1742   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1743      prefix = "";      prefix = "";
1744      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1745      kernel += 6;      kernel += 6;
1746   }   }
1747    
1748   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1749      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1750    
1751        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1752    
1753      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1754                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1755          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1756                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1757                              kernel + strlen(prefix)))       checkType, line);
1758                      break;   if (!line) break;  /* not found in this entry */
1759              }  
1760                 if (line && line->type != LT_MENUENTRY &&
1761              /* have to check multiboot lines too */   line->numElements >= 2) {
1762              if (entry->multiboot) {      rootspec = getRootSpecifier(line->elements[1].item);
1763                  while (line && line->type != LT_MBMODULE) line = line->next;      if (!strcmp(line->elements[1].item +
1764                  if (line && line->numElements >= 2 && !entry->skip) {   ((rootspec != NULL) ? strlen(rootspec) : 0),
1765                      rootspec = getRootSpecifier(line->elements[1].item);   kernel + strlen(prefix)))
1766                      if (!strcmp(line->elements[1].item  +   break;
1767                                  ((rootspec != NULL) ? strlen(rootspec) : 0),   }
1768                                  kernel + strlen(prefix)))   if(line->type == LT_MENUENTRY &&
1769                          break;   !strcmp(line->elements[1].item, kernel))
1770                  }      break;
1771              }      }
1772    
1773      i++;      /* make sure this entry has a kernel identifier; this skips
1774         * non-Linux boot entries (could find netbsd etc, though, which is
1775         * unfortunate)
1776         */
1777        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1778     break; /* found 'im! */
1779   }   }
1780    
1781   if (index) *index = i;   if (index) *index = i;
1782      }      }
1783    
     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);  
     }  
   
1784      return entry;      return entry;
1785  }  }
1786    
# Line 1200  void markRemovedImage(struct grubConfig Line 1859  void markRemovedImage(struct grubConfig
1859        const char * prefix) {        const char * prefix) {
1860      struct singleEntry * entry;      struct singleEntry * entry;
1861    
1862      if (!image) return;      if (!image)
1863     return;
1864    
1865        /* check and see if we're removing the default image */
1866        if (isdigit(*image)) {
1867     entry = findEntryByPath(cfg, image, prefix, NULL);
1868     if(entry)
1869        entry->skip = 1;
1870     return;
1871        }
1872    
1873      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1874   entry->skip = 1;   entry->skip = 1;
# Line 1227  void setDefaultImage(struct grubConfig * Line 1895  void setDefaultImage(struct grubConfig *
1895    
1896      /* 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
1897         changes */         changes */
1898      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1899     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1900        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1901        return;        return;
1902    
# Line 1286  void displayEntry(struct singleEntry * e Line 1955  void displayEntry(struct singleEntry * e
1955      char * root = NULL;      char * root = NULL;
1956      int i;      int i;
1957    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1958      printf("index=%d\n", index);      printf("index=%d\n", index);
1959    
1960      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1961        if (!line) {
1962            printf("non linux entry\n");
1963            return;
1964        }
1965    
1966        printf("kernel=%s%s\n", prefix, line->elements[1].item);
1967    
1968      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1969   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1980  void displayEntry(struct singleEntry * e
1980   }   }
1981   printf("\"\n");   printf("\"\n");
1982      } else {      } else {
1983   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1984   if (line) {   if (line) {
1985      char * s;      char * s;
1986    
# Line 1334  void displayEntry(struct singleEntry * e Line 2004  void displayEntry(struct singleEntry * e
2004      }      }
2005    
2006      if (!root) {      if (!root) {
2007   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2008   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2009      root=line->elements[1].item;      root=line->elements[1].item;
2010      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2019  void displayEntry(struct singleEntry * e
2019   printf("root=%s\n", s);   printf("root=%s\n", s);
2020      }      }
2021    
2022      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2023    
2024      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2025   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1360  void displayEntry(struct singleEntry * e Line 2027  void displayEntry(struct singleEntry * e
2027      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2028   printf("\n");   printf("\n");
2029      }      }
2030    
2031        line = getLineByType(LT_TITLE, entry->lines);
2032        if (line) {
2033     printf("title=%s\n", line->elements[1].item);
2034        } else {
2035     char * title;
2036     line = getLineByType(LT_MENUENTRY, entry->lines);
2037     title = grub2ExtractTitle(line);
2038     if (title)
2039        printf("title=%s\n", title);
2040        }
2041  }  }
2042    
2043  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2047  int parseSysconfigGrub(int * lbaPtr, cha
2047      char * start;      char * start;
2048      char * param;      char * param;
2049    
2050      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2051      if (!in) return 1;      if (!in) return 1;
2052    
2053      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 2109  int displayInfo(struct grubConfig * conf
2109   return 1;   return 1;
2110      }      }
2111    
2112      /* 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
2113         be a better way */         be a better way */
2114      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2115   dumpSysconfigGrub();   dumpSysconfigGrub();
2116      } else {      } else {
2117   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2118   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2119      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2120   }   }
2121    
2122   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2123   if (line) printf("lba\n");   if (line) printf("lba\n");
2124      }      }
2125    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2134  int displayInfo(struct grubConfig * conf
2134      return 0;      return 0;
2135  }  }
2136    
2137    struct singleLine * addLineTmpl(struct singleEntry * entry,
2138     struct singleLine * tmplLine,
2139     struct singleLine * prevLine,
2140     const char * val,
2141     struct configFileInfo * cfi)
2142    {
2143        struct singleLine * newLine = lineDup(tmplLine);
2144    
2145        if (val) {
2146     /* override the inherited value with our own.
2147     * This is a little weak because it only applies to elements[1]
2148     */
2149     if (newLine->numElements > 1)
2150        removeElement(newLine, 1);
2151     insertElement(newLine, val, 1, cfi);
2152    
2153     /* but try to keep the rootspec from the template... sigh */
2154     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2155        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2156        if (rootspec != NULL) {
2157     free(newLine->elements[1].item);
2158     newLine->elements[1].item =
2159        sdupprintf("%s%s", rootspec, val);
2160        }
2161     }
2162        }
2163    
2164        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2165          newLine->elements[0].item : "");
2166    
2167        if (!entry->lines) {
2168     /* first one on the list */
2169     entry->lines = newLine;
2170        } else if (prevLine) {
2171     /* add after prevLine */
2172     newLine->next = prevLine->next;
2173     prevLine->next = newLine;
2174        }
2175    
2176        return newLine;
2177    }
2178    
2179  /* val may be NULL */  /* val may be NULL */
2180  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2181       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2182       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2183       char * val) {       const char * val) {
2184      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2185      int i;      struct keywordTypes * kw;
2186        struct singleLine tmpl;
2187    
2188      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2189   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2190      if (type != LT_TITLE || !cfi->titleBracketed)       */
2191          if (!cfi->keywords[i].key) abort();  
2192        if (type == LT_TITLE && cfi->titleBracketed) {
2193     /* we're doing a bracketed title (zipl) */
2194     tmpl.type = type;
2195     tmpl.numElements = 1;
2196     tmpl.elements = alloca(sizeof(*tmpl.elements));
2197     tmpl.elements[0].item = alloca(strlen(val)+3);
2198     sprintf(tmpl.elements[0].item, "[%s]", val);
2199     tmpl.elements[0].indent = "";
2200     val = NULL;
2201        } else if (type == LT_MENUENTRY) {
2202     char *lineend = "--class gnu-linux --class gnu --class os {";
2203     if (!val) {
2204        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2205        abort();
2206     }
2207     kw = getKeywordByType(type, cfi);
2208     if (!kw) {
2209        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2210        abort();
2211     }
2212     tmpl.indent = "";
2213     tmpl.type = type;
2214     tmpl.numElements = 3;
2215     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2216     tmpl.elements[0].item = kw->key;
2217     tmpl.elements[0].indent = alloca(2);
2218     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2219     tmpl.elements[1].item = (char *)val;
2220     tmpl.elements[1].indent = alloca(2);
2221     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2222     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2223     strcpy(tmpl.elements[2].item, lineend);
2224     tmpl.elements[2].indent = "";
2225        } else {
2226     kw = getKeywordByType(type, cfi);
2227     if (!kw) {
2228        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2229        abort();
2230     }
2231     tmpl.type = type;
2232     tmpl.numElements = val ? 2 : 1;
2233     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2234     tmpl.elements[0].item = kw->key;
2235     tmpl.elements[0].indent = alloca(2);
2236     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2237     if (val) {
2238        tmpl.elements[1].item = (char *)val;
2239        tmpl.elements[1].indent = "";
2240     }
2241        }
2242    
2243      /* 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
2244         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2245         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
2246         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2247         differently from the rest) */         differently from the rest) */
2248      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2249   line = entry->lines;   if (line->numElements) prev = line;
2250   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2251   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;  
2252      }      }
2253    
2254      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2255          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2256          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2257          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2258          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2259          line->elements[0].indent = malloc(2);   else
2260          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2261          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2262             if (menuEntry)
2263          if (val) {      tmpl.indent = "\t";
2264              line->elements[1].item = val;   else if (prev == entry->lines)
2265              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2266          }   else
2267      } 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("");  
2268      }      }
2269    
2270      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2271  }  }
2272    
2273  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2292  void removeLine(struct singleEntry * ent
2292      free(line);      free(line);
2293  }  }
2294    
2295    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2296    {
2297        struct singleLine newLine = {
2298     .indent = tmplLine->indent,
2299     .type = tmplLine->type,
2300     .next = tmplLine->next,
2301        };
2302        int firstQuotedItem = -1;
2303        int quoteLen = 0;
2304        int j;
2305        int element = 0;
2306        char *c;
2307    
2308        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2309        strcpy(c, tmplLine->elements[0].item);
2310        insertElement(&newLine, c, element++, cfi);
2311        free(c);
2312        c = NULL;
2313    
2314        for (j = 1; j < tmplLine->numElements; j++) {
2315     if (firstQuotedItem == -1) {
2316        quoteLen += strlen(tmplLine->elements[j].item);
2317        
2318        if (isquote(tmplLine->elements[j].item[0])) {
2319     firstQuotedItem = j;
2320            quoteLen += strlen(tmplLine->elements[j].indent);
2321        } else {
2322     c = malloc(quoteLen + 1);
2323     strcpy(c, tmplLine->elements[j].item);
2324     insertElement(&newLine, c, element++, cfi);
2325     free(c);
2326     quoteLen = 0;
2327        }
2328     } else {
2329        int itemlen = strlen(tmplLine->elements[j].item);
2330        quoteLen += itemlen;
2331        quoteLen += strlen(tmplLine->elements[j].indent);
2332        
2333        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2334     c = malloc(quoteLen + 1);
2335     c[0] = '\0';
2336     for (int i = firstQuotedItem; i < j+1; i++) {
2337        strcat(c, tmplLine->elements[i].item);
2338        strcat(c, tmplLine->elements[i].indent);
2339     }
2340     insertElement(&newLine, c, element++, cfi);
2341     free(c);
2342    
2343     firstQuotedItem = -1;
2344     quoteLen = 0;
2345        }
2346     }
2347        }
2348        while (tmplLine->numElements)
2349     removeElement(tmplLine, 0);
2350        if (tmplLine->elements)
2351     free(tmplLine->elements);
2352    
2353        tmplLine->numElements = newLine.numElements;
2354        tmplLine->elements = newLine.elements;
2355    }
2356    
2357    static void insertElement(struct singleLine * line,
2358      const char * item, int insertHere,
2359      struct configFileInfo * cfi)
2360    {
2361        struct keywordTypes * kw;
2362        char indent[2] = "";
2363    
2364        /* sanity check */
2365        if (insertHere > line->numElements) {
2366     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2367      insertHere, line->numElements);
2368     insertHere = line->numElements;
2369        }
2370    
2371        line->elements = realloc(line->elements, (line->numElements + 1) *
2372         sizeof(*line->elements));
2373        memmove(&line->elements[insertHere+1],
2374        &line->elements[insertHere],
2375        (line->numElements - insertHere) *
2376        sizeof(*line->elements));
2377        line->elements[insertHere].item = strdup(item);
2378    
2379        kw = getKeywordByType(line->type, cfi);
2380    
2381        if (line->numElements == 0) {
2382     indent[0] = '\0';
2383        } else if (insertHere == 0) {
2384     indent[0] = kw->nextChar;
2385        } else if (kw->separatorChar != '\0') {
2386     indent[0] = kw->separatorChar;
2387        } else {
2388     indent[0] = ' ';
2389        }
2390    
2391        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2392     /* move the end-of-line forward */
2393     line->elements[insertHere].indent =
2394        line->elements[insertHere-1].indent;
2395     line->elements[insertHere-1].indent = strdup(indent);
2396        } else {
2397     line->elements[insertHere].indent = strdup(indent);
2398        }
2399    
2400        line->numElements++;
2401    
2402        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2403          line->elements[0].item,
2404          line->elements[insertHere].item,
2405          line->elements[insertHere].indent,
2406          insertHere);
2407    }
2408    
2409    static void removeElement(struct singleLine * line, int removeHere) {
2410        int i;
2411    
2412        /* sanity check */
2413        if (removeHere >= line->numElements) return;
2414    
2415        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2416          removeHere, line->elements[removeHere].item);
2417    
2418        free(line->elements[removeHere].item);
2419    
2420        if (removeHere > 1) {
2421     /* previous argument gets this argument's post-indentation */
2422     free(line->elements[removeHere-1].indent);
2423     line->elements[removeHere-1].indent =
2424        line->elements[removeHere].indent;
2425        } else {
2426     free(line->elements[removeHere].indent);
2427        }
2428    
2429        /* now collapse the array, but don't bother to realloc smaller */
2430        for (i = removeHere; i < line->numElements - 1; i++)
2431     line->elements[i] = line->elements[i + 1];
2432    
2433        line->numElements--;
2434    }
2435    
2436  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2437      char * first, * second;      char * first, * second;
2438      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2455  int updateActualImage(struct grubConfig
2455      struct singleEntry * entry;      struct singleEntry * entry;
2456      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2457      int index = 0;      int index = 0;
2458      int i, j, k;      int i, k;
2459      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2460      const char ** arg;      const char ** arg;
2461      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2462      int firstElement;      int firstElement;
2463      int *usedElements, *usedArgs;      int *usedElements;
2464        int doreplace;
2465    
2466      if (!image) return 0;      if (!image) return 0;
2467    
# Line 1609  int updateActualImage(struct grubConfig Line 2488  int updateActualImage(struct grubConfig
2488   }   }
2489      }      }
2490    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2491    
2492      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2493   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2494    
2495      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2496   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2497    
2498      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2499    
2500      k = 0;   if (multibootArgs && !entry->multiboot)
2501      for (arg = newArgs; *arg; arg++)      continue;
2502          k++;  
2503      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2504     * LT_KERNELARGS, use that.  Otherwise use
2505     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2506     */
2507     if (useKernelArgs) {
2508        line = getLineByType(LT_KERNELARGS, entry->lines);
2509        if (!line) {
2510     /* no LT_KERNELARGS, need to add it */
2511     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2512           cfg->secondaryIndent, NULL);
2513        }
2514        firstElement = 1;
2515    
2516      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2517   index++;      line = getLineByType(LT_HYPER, entry->lines);
2518        if (!line) {
2519     /* a multiboot entry without LT_HYPER? */
2520     continue;
2521        }
2522        firstElement = 2;
2523    
2524   line = entry->lines;   } else {
2525   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2526   if (!line) continue;      if (!line) {
2527   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2528     continue;
2529          if (entry->multiboot && !multibootArgs) {      }
2530              /* 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;  
2531   }   }
2532    
2533   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2534      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2535      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2536     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2537        /* this is a multiboot entry, make sure there's
2538         * -- on the args line
2539         */
2540        for (i = firstElement; i < line->numElements; i++) {
2541     if (!strcmp(line->elements[i].item, "--"))
2542        break;
2543        }
2544        if (i == line->numElements) {
2545     /* assume all existing args are kernel args,
2546     * prepend -- to make it official
2547     */
2548     insertElement(line, "--", firstElement, cfg->cfi);
2549     i = firstElement;
2550        }
2551        if (!multibootArgs) {
2552     /* kernel args start after the -- */
2553     firstElement = i + 1;
2554        }
2555     } else if (cfg->cfi->mbConcatArgs) {
2556        /* this is a non-multiboot entry, remove hyper args */
2557        for (i = firstElement; i < line->numElements; i++) {
2558     if (!strcmp(line->elements[i].item, "--"))
2559        break;
2560        }
2561        if (i < line->numElements) {
2562     /* remove args up to -- */
2563     while (strcmp(line->elements[firstElement].item, "--"))
2564        removeElement(line, firstElement);
2565     /* remove -- */
2566     removeElement(line, firstElement);
2567        }
2568   }   }
2569    
2570          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2571    
2572          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2573   for (arg = newArgs; *arg; arg++) {  
2574              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2575      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2576     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2577        !strcmp(line->elements[i].item, "--"))
2578     {
2579        /* reached the end of hyper args, insert here */
2580        doreplace = 0;
2581        break;  
2582     }
2583                  if (usedElements[i])                  if (usedElements[i])
2584                      continue;                      continue;
2585   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2586                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2587      break;      break;
2588                  }                  }
2589              }              }
     chptr = strchr(*arg, '=');  
2590    
2591      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2592   /* replace */   /* direct replacement */
2593   free(line->elements[i].item);   free(line->elements[i].item);
2594   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("");  
  }  
2595    
2596   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2597   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2598      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2599   /* append */   if (rootLine) {
2600   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2601   (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(" ");  
2602   } else {   } else {
2603      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2604         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2605   }   }
2606        }
2607    
2608   line->numElements++;      else {
2609     /* insert/append */
2610     insertElement(line, *arg, i, cfg->cfi);
2611     usedElements = realloc(usedElements, line->numElements *
2612           sizeof(*usedElements));
2613     memmove(&usedElements[i + 1], &usedElements[i],
2614     line->numElements - i - 1);
2615     usedElements[i] = 1;
2616    
2617   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2618     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2619     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2620   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2621      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2622      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2623   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2624   }   }
2625      }      }
             k++;  
2626   }   }
2627    
2628          free(usedElements);          free(usedElements);
2629    
  /* 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? */  
2630   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2631      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2632   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2633        !strcmp(line->elements[i].item, "--"))
2634        /* reached the end of hyper args, stop here */
2635        break;
2636     if (!argMatch(line->elements[i].item, *arg)) {
2637        removeElement(line, i);
2638      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;  
2639   }   }
2640        }
2641   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2642        if (useRoot && !strncmp(*arg, "root=", 5)) {
2643   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2644      line->elements[j - 1] = line->elements[j];   if (rootLine)
2645        removeLine(entry, rootLine);
  line->numElements--;  
2646      }      }
2647   }   }
2648    
# Line 1760  int updateActualImage(struct grubConfig Line 2653  int updateActualImage(struct grubConfig
2653   }   }
2654      }      }
2655    
     free(usedArgs);  
2656      free(newArgs);      free(newArgs);
2657      free(oldArgs);      free(oldArgs);
2658    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2678  int updateImage(struct grubConfig * cfg,
2678      return rc;      return rc;
2679  }  }
2680    
2681    int updateInitrd(struct grubConfig * cfg, const char * image,
2682                     const char * prefix, const char * initrd) {
2683        struct singleEntry * entry;
2684        struct singleLine * line, * kernelLine, *endLine = NULL;
2685        int index = 0;
2686    
2687        if (!image) return 0;
2688    
2689        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2690            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2691            if (!kernelLine) continue;
2692    
2693            line = getLineByType(LT_INITRD, entry->lines);
2694            if (line)
2695                removeLine(entry, line);
2696            if (prefix) {
2697                int prefixLen = strlen(prefix);
2698                if (!strncmp(initrd, prefix, prefixLen))
2699                    initrd += prefixLen;
2700            }
2701     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2702     if (endLine)
2703        removeLine(entry, endLine);
2704            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2705            if (!line)
2706        return 1;
2707     if (endLine) {
2708        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2709                if (!line)
2710     return 1;
2711     }
2712    
2713            break;
2714        }
2715    
2716        return 0;
2717    }
2718    
2719  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2720      int fd;      int fd;
2721      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2739  int checkDeviceBootloader(const char * d
2739      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2740   return 0;   return 0;
2741    
2742      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2743   offset = boot[2] + 2;   offset = boot[2] + 2;
2744      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2745   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2746      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2747   offset = boot[1] + 2;        offset = boot[1] + 2;
2748            /*
2749     * it looks like grub, when copying stage1 into the mbr, patches stage1
2750     * right after the JMP location, replacing other instructions such as
2751     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2752     * different bytes.
2753     */
2754          if ((bootSect[offset + 1] == NOOP_OPCODE)
2755      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2756     offset = offset + 3;
2757          }
2758      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2759   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2760      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2896  int checkForLilo(struct grubConfig * con
2896      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2897  }  }
2898    
2899    int checkForGrub2(struct grubConfig * config) {
2900        if (!access("/etc/grub.d/", R_OK))
2901     return 2;
2902    
2903        return 1;
2904    }
2905    
2906  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2907      int fd;      int fd;
2908      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2923  int checkForGrub(struct grubConfig * con
2923      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2924   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2925   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2926     close(fd);
2927     return 1;
2928        }
2929        close(fd);
2930    
2931        return checkDeviceBootloader(boot, bootSect);
2932    }
2933    
2934    int checkForExtLinux(struct grubConfig * config) {
2935        int fd;
2936        unsigned char bootSect[512];
2937        char * boot;
2938        char executable[] = "/boot/extlinux/extlinux";
2939    
2940        printf("entered: checkForExtLinux()\n");
2941    
2942        if (parseSysconfigGrub(NULL, &boot))
2943     return 0;
2944    
2945        /* assume grub is not installed -- not an error condition */
2946        if (!boot)
2947     return 0;
2948    
2949        fd = open(executable, O_RDONLY);
2950        if (fd < 0)
2951     /* this doesn't exist if grub hasn't been installed */
2952     return 0;
2953    
2954        if (read(fd, bootSect, 512) != 512) {
2955     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2956     executable, strerror(errno));
2957   return 1;   return 1;
2958      }      }
2959      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2972  static char * getRootSpecifier(char * st
2972      return rootspec;      return rootspec;
2973  }  }
2974    
2975    static char * getInitrdVal(struct grubConfig * config,
2976       const char * prefix, struct singleLine *tmplLine,
2977       const char * newKernelInitrd,
2978       char ** extraInitrds, int extraInitrdCount)
2979    {
2980        char *initrdVal, *end;
2981        int i;
2982        size_t totalSize;
2983        size_t prefixLen;
2984        char separatorChar;
2985    
2986        prefixLen = strlen(prefix);
2987        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2988    
2989        for (i = 0; i < extraInitrdCount; i++) {
2990     totalSize += sizeof(separatorChar);
2991     totalSize += strlen(extraInitrds[i]) - prefixLen;
2992        }
2993    
2994        initrdVal = end = malloc(totalSize);
2995    
2996        end = stpcpy (end, newKernelInitrd + prefixLen);
2997    
2998        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2999        for (i = 0; i < extraInitrdCount; i++) {
3000     const char *extraInitrd;
3001     int j;
3002    
3003     extraInitrd = extraInitrds[i] + prefixLen;
3004     /* Don't add entries that are already there */
3005     if (tmplLine != NULL) {
3006        for (j = 2; j < tmplLine->numElements; j++)
3007     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3008        break;
3009    
3010        if (j != tmplLine->numElements)
3011     continue;
3012     }
3013    
3014     *end++ = separatorChar;
3015     end = stpcpy(end, extraInitrd);
3016        }
3017    
3018        return initrdVal;
3019    }
3020    
3021  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3022           const char * prefix,           const char * prefix,
3023   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
3024   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
3025     char ** extraInitrds, int extraInitrdCount,
3026                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
3027      struct singleEntry * new;      struct singleEntry * new;
3028      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3029      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3030      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3031    
3032      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3033    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3057  int addNewKernel(struct grubConfig * con
3057      config->entries = new;      config->entries = new;
3058    
3059      /* copy/update from the template */      /* copy/update from the template */
3060      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3061        if (newKernelInitrd)
3062     needs |= NEED_INITRD;
3063      if (newMBKernel) {      if (newMBKernel) {
3064          needs |= KERNEL_MB;          needs |= NEED_MB;
3065          new->multiboot = 1;          new->multiboot = 1;
3066      }      }
3067    
3068      if (template) {      if (template) {
3069   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3070      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3071      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3072   indent = tmplLine->indent;   {
3073        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3074    
3075      /* skip comments */      /* skip comments */
3076      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3077      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3078      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3079    
3080      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3081      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3082     if (!template->multiboot && (needs & NEED_MB)) {
3083              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3084                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3085                  struct singleLine *l;       * hypervisor at the same time.
3086                  needs &= ~ KERNEL_MB;       */
3087        if (config->cfi->mbHyperFirst) {
3088                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3089                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3090                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3091                      newMBKernel + strlen(prefix));
3092                  tmplLine = lastLine;   /* set up for adding the kernel line */
3093                  if (!new->lines) {   free(tmplLine->indent);
3094                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3095                  } else {   needs &= ~NEED_MB;
3096                      newLine->next = l;      }
3097                      newLine = l;      if (needs & NEED_KERNEL) {
3098                  }   /* use addLineTmpl to preserve line elements,
3099                  continue;   * otherwise we could just call addLine.  Unfortunately
3100              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3101                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3102                  continue; /* don't need multiboot kernel here */   * change below.
3103              }   */
3104     struct keywordTypes * mbm_kw =
3105        getKeywordByType(LT_MBMODULE, config->cfi);
3106     if (mbm_kw) {
3107        tmplLine->type = LT_MBMODULE;
3108        free(tmplLine->elements[0].item);
3109        tmplLine->elements[0].item = strdup(mbm_kw->key);
3110     }
3111     newLine = addLineTmpl(new, tmplLine, newLine,
3112          newKernelPath + strlen(prefix), config->cfi);
3113     needs &= ~NEED_KERNEL;
3114        }
3115        if (needs & NEED_MB) { /* !mbHyperFirst */
3116     newLine = addLine(new, config->cfi, LT_HYPER,
3117      config->secondaryIndent,
3118      newMBKernel + strlen(prefix));
3119     needs &= ~NEED_MB;
3120        }
3121     } else if (needs & NEED_KERNEL) {
3122        newLine = addLineTmpl(new, tmplLine, newLine,
3123      newKernelPath + strlen(prefix), config->cfi);
3124        needs &= ~NEED_KERNEL;
3125     }
3126    
3127      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3128   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3129   new->lines = newLine;   if (needs & NEED_MB) {
3130      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3131   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3132   newLine = newLine->next;      needs &= ~NEED_MB;
3133      }   }
3134    
3135        } else if (tmplLine->type == LT_MBMODULE &&
3136           tmplLine->numElements >= 2) {
3137     if (new->multiboot) {
3138        if (needs & NEED_KERNEL) {
3139     newLine = addLineTmpl(new, tmplLine, newLine,
3140          newKernelPath +
3141          strlen(prefix), config->cfi);
3142     needs &= ~NEED_KERNEL;
3143        } else if (config->cfi->mbInitRdIsModule &&
3144           (needs & NEED_INITRD)) {
3145     char *initrdVal;
3146     initrdVal = getInitrdVal(config, prefix, tmplLine,
3147     newKernelInitrd, extraInitrds,
3148     extraInitrdCount);
3149     newLine = addLineTmpl(new, tmplLine, newLine,
3150          initrdVal, config->cfi);
3151     free(initrdVal);
3152     needs &= ~NEED_INITRD;
3153        }
3154     } else if (needs & NEED_KERNEL) {
3155        /* template is multi but new is not,
3156         * insert the kernel in the first module slot
3157         */
3158        tmplLine->type = LT_KERNEL;
3159        free(tmplLine->elements[0].item);
3160        tmplLine->elements[0].item =
3161     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3162        newLine = addLineTmpl(new, tmplLine, newLine,
3163      newKernelPath + strlen(prefix), config->cfi);
3164        needs &= ~NEED_KERNEL;
3165     } else if (needs & NEED_INITRD) {
3166        char *initrdVal;
3167        /* template is multi but new is not,
3168         * insert the initrd in the second module slot
3169         */
3170        tmplLine->type = LT_INITRD;
3171        free(tmplLine->elements[0].item);
3172        tmplLine->elements[0].item =
3173     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3174        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3175        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3176        free(initrdVal);
3177        needs &= ~NEED_INITRD;
3178     }
3179    
     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));  
                 }  
3180      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3181      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3182   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3183   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3184                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3185                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3186                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3187                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3188                  }       */
3189                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3190                  if (rootspec != NULL) {   char *initrdVal;
3191                      newLine->elements[1].item = sdupprintf("%s%s",  
3192                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3193                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3194                                                             strlen(prefix));    config->secondaryIndent,
3195                  } else {    initrdVal);
3196                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3197                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3198                  }      }
3199              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3200                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3201   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3202                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3203                      free(newLine->elements[0].item);      free(initrdVal);
3204                      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);  
3205   }   }
3206    
3207   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3208   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3209   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3210     char *nkt = malloc(strlen(newKernelTitle)+3);
3211     strcpy(nkt, "'");
3212     strcat(nkt, newKernelTitle);
3213     strcat(nkt, "'");
3214     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3215     free(nkt);
3216     needs &= ~NEED_TITLE;
3217      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3218                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3219                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3220                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3221                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3222                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3223                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3224                                             newLine->numElements);     config->cfi->titleBracketed) {
3225        /* addLineTmpl doesn't handle titleBracketed */
3226                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3227                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3228                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3229                  newLine->numElements = 1;   }
3230              }      } else if (tmplLine->type == LT_ECHO) {
3231        requote(tmplLine, config->cfi);
3232        static const char *prefix = "'Loading ";
3233        if (tmplLine->numElements > 1 &&
3234        strstr(tmplLine->elements[1].item, prefix) &&
3235        masterLine->next && masterLine->next->type == LT_KERNEL) {
3236     char *newTitle = malloc(strlen(prefix) +
3237     strlen(newKernelTitle) + 2);
3238    
3239     strcpy(newTitle, prefix);
3240     strcat(newTitle, newKernelTitle);
3241     strcat(newTitle, "'");
3242     newLine = addLine(new, config->cfi, LT_ECHO,
3243     tmplLine->indent, newTitle);
3244     free(newTitle);
3245        } else {
3246     /* pass through other lines from the template */
3247     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3248     config->cfi);
3249        }
3250        } else {
3251     /* pass through other lines from the template */
3252     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3253        }
3254   }   }
3255    
3256      } else {      } else {
3257   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3258      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3259     */
3260     switch (config->cfi->entryStart) {
3261        case LT_KERNEL:
3262     if (new->multiboot && config->cfi->mbHyperFirst) {
3263        /* fall through to LT_HYPER */
3264     } else {
3265        newLine = addLine(new, config->cfi, LT_KERNEL,
3266          config->primaryIndent,
3267          newKernelPath + strlen(prefix));
3268        needs &= ~NEED_KERNEL;
3269        break;
3270     }
3271    
3272        case LT_HYPER:
3273     newLine = addLine(new, config->cfi, LT_HYPER,
3274      config->primaryIndent,
3275      newMBKernel + strlen(prefix));
3276     needs &= ~NEED_MB;
3277   break;   break;
         }  
3278    
3279   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3280      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3281       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3282       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3283      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3284       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3285      default:        config->primaryIndent, nkt);
3286                  /* zipl strikes again */   free(nkt);
3287                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3288                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3289                      chptr = newKernelTitle;   break;
3290                      type = LT_TITLE;      }
3291                      break;      case LT_TITLE:
3292                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3293                      abort();   char * templabel;
3294                  }   int x = 0, y = 0;
3295   }  
3296     templabel = strdup(newKernelTitle);
3297     while( templabel[x]){
3298     if( templabel[x] == ' ' ){
3299     y = x;
3300     while( templabel[y] ){
3301     templabel[y] = templabel[y+1];
3302     y++;
3303     }
3304     }
3305     x++;
3306     }
3307     newLine = addLine(new, config->cfi, LT_TITLE,
3308      config->primaryIndent, templabel);
3309     free(templabel);
3310     }else{
3311     newLine = addLine(new, config->cfi, LT_TITLE,
3312      config->primaryIndent, newKernelTitle);
3313     }
3314     needs &= ~NEED_TITLE;
3315     break;
3316    
3317   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3318   new->lines = newLine;   abort();
3319     }
3320      }      }
3321    
3322      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3323          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3324              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3325                                config->secondaryIndent,       */
3326                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3327          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3328              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3329                                config->secondaryIndent,    newKernelTitle);
3330                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3331          /* don't need to check for title as it's guaranteed to have been      }
3332           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3333           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3334          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3335              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3336                                config->secondaryIndent,   needs &= ~NEED_MB;
3337                                newKernelInitrd + strlen(prefix));      }
3338      } else {      if (needs & NEED_KERNEL) {
3339          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3340              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3341                                config->secondaryIndent,        config->cfi)) ?
3342                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3343          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3344              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3345                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3346                                newKernelTitle);      }
3347          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3348              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3349                                config->secondaryIndent,    config->secondaryIndent,
3350                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3351     needs &= ~NEED_MB;
3352        }
3353        if (needs & NEED_INITRD) {
3354     char *initrdVal;
3355     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3356     newLine = addLine(new, config->cfi,
3357      (new->multiboot && getKeywordByType(LT_MBMODULE,
3358          config->cfi)) ?
3359      LT_MBMODULE : LT_INITRD,
3360      config->secondaryIndent,
3361      initrdVal);
3362     free(initrdVal);
3363     needs &= ~NEED_INITRD;
3364        }
3365        if (needs & NEED_END) {
3366     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3367     config->secondaryIndent, NULL);
3368     needs &= ~NEED_END;
3369        }
3370    
3371        if (needs) {
3372     printf(_("grubby: needs=%d, aborting\n"), needs);
3373     abort();
3374      }      }
3375    
3376      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3379  int addNewKernel(struct grubConfig * con
3379      return 0;      return 0;
3380  }  }
3381    
3382    static void traceback(int signum)
3383    {
3384        void *array[40];
3385        size_t size;
3386    
3387        signal(SIGSEGV, SIG_DFL);
3388        memset(array, '\0', sizeof (array));
3389        size = backtrace(array, 40);
3390    
3391        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3392                (unsigned long)size);
3393        backtrace_symbols_fd(array, size, STDERR_FILENO);
3394        exit(1);
3395    }
3396    
3397  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3398      poptContext optCon;      poptContext optCon;
3399      char * grubConfig = NULL;      const char * grubConfig = NULL;
3400      char * outputFile = NULL;      char * outputFile = NULL;
3401      int arg = 0;      int arg = 0;
3402      int flags = 0;      int flags = 0;
3403      int badImageOkay = 0;      int badImageOkay = 0;
3404        int configureGrub2 = 0;
3405      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3406      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3407        int configureExtLinux = 0;
3408      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3409        int extraInitrdCount = 0;
3410      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3411      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3412      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3422  int main(int argc, const char ** argv) {
3422      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3423      char * removeArgs = NULL;      char * removeArgs = NULL;
3424      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3425        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3426      const char * chptr = NULL;      const char * chptr = NULL;
3427      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3428      struct grubConfig * config;      struct grubConfig * config;
3429      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3430      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3431      int displayDefault = 0;      int displayDefault = 0;
3432        int displayDefaultIndex = 0;
3433        int displayDefaultTitle = 0;
3434      struct poptOption options[] = {      struct poptOption options[] = {
3435   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3436      _("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 3461  int main(int argc, const char ** argv) {
3461        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3462        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3463        "template"), NULL },        "template"), NULL },
3464     { "debug", 0, 0, &debug, 0,
3465        _("print debugging information for failures") },
3466   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3467      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3468     { "default-index", 0, 0, &displayDefaultIndex, 0,
3469        _("display the index of the default kernel") },
3470     { "default-title", 0, 0, &displayDefaultTitle, 0,
3471        _("display the title of the default kernel") },
3472   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3473      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3474     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3475        _("configure extlinux bootloader (from syslinux)") },
3476   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3477      _("configure grub bootloader") },      _("configure grub bootloader") },
3478     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3479        _("configure grub2 bootloader") },
3480   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3481      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3482      _("kernel-path") },      _("kernel-path") },
3483   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3484      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3485     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3486        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3487   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3488      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3489   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3520  int main(int argc, const char ** argv) {
3520   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3521      };      };
3522    
3523        useextlinuxmenu=0;
3524    
3525        signal(SIGSEGV, traceback);
3526    
3527      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3528      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3529    
# Line 2391  int main(int argc, const char ** argv) { Line 3533  int main(int argc, const char ** argv) {
3533      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3534      exit(0);      exit(0);
3535      break;      break;
3536      case 'i':
3537        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3538         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3539        } else {
3540     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3541     return 1;
3542        }
3543        break;
3544   }   }
3545      }      }
3546    
# Line 2406  int main(int argc, const char ** argv) { Line 3556  int main(int argc, const char ** argv) {
3556   return 1;   return 1;
3557      }      }
3558    
3559      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3560   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3561     configureExtLinux ) > 1) {
3562   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3563   return 1;   return 1;
3564      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3565   fprintf(stderr,   fprintf(stderr,
3566      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3567   return 1;   return 1;
3568        } else if (configureGrub2) {
3569     cfi = &grub2ConfigType;
3570      } else if (configureLilo) {      } else if (configureLilo) {
3571   cfi = &liloConfigType;   cfi = &liloConfigType;
3572      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3579  int main(int argc, const char ** argv) {
3579          cfi = &siloConfigType;          cfi = &siloConfigType;
3580      } else if (configureZipl) {      } else if (configureZipl) {
3581          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3582        } else if (configureExtLinux) {
3583     cfi = &extlinuxConfigType;
3584     useextlinuxmenu=1;
3585      }      }
3586    
3587      if (!cfi) {      if (!cfi) {
3588            if (grub2FindConfig(&grub2ConfigType))
3589        cfi = &grub2ConfigType;
3590     else
3591        #ifdef __ia64__        #ifdef __ia64__
3592   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3593        #elif __powerpc__        #elif __powerpc__
3594   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3595        #elif __sparc__        #elif __sparc__
3596          cfi = &siloConfigType;              cfi = &siloConfigType;
3597        #elif __s390__        #elif __s390__
3598          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3599        #elif __s390x__        #elif __s390x__
3600          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3601        #else        #else
3602   cfi = &grubConfigType;      cfi = &grubConfigType;
3603        #endif        #endif
3604      }      }
3605    
3606      if (!grubConfig)      if (!grubConfig) {
3607   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3608        grubConfig = cfi->findConfig(cfi);
3609     if (!grubConfig)
3610        grubConfig = cfi->defaultConfig;
3611        }
3612    
3613      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3614    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3615    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3616   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3617    "specified option"));    "specified option"));
3618   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3628  int main(int argc, const char ** argv) {
3628      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3629   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3630   return 1;   return 1;
3631      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3632    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3633    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3634   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3635   return 1;   return 1;
3636      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3655  int main(int argc, const char ** argv) {
3655   defaultKernel = NULL;   defaultKernel = NULL;
3656      }      }
3657    
3658      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3659   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3660   "is used\n"));   "is used\n"));
3661   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3663  int main(int argc, const char ** argv) {
3663    
3664      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3665   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3666          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3667   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3668   return 1;   return 1;
3669      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3683  int main(int argc, const char ** argv) {
3683   bootPrefix = "";   bootPrefix = "";
3684      }      }
3685    
3686        if (!cfi->mbAllowExtraInitRds &&
3687     extraInitrdCount > 0) {
3688     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3689     return 1;
3690        }
3691    
3692      if (bootloaderProbe) {      if (bootloaderProbe) {
3693   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3694   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3695    
3696   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3697      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3698        gconfig = readConfig(grub2config, &grub2ConfigType);
3699        if (!gconfig)
3700     gr2c = 1;
3701        else
3702     gr2c = checkForGrub2(gconfig);
3703     }
3704    
3705     const char *grubconfig = grubFindConfig(&grubConfigType);
3706     if (!access(grubconfig, F_OK)) {
3707        gconfig = readConfig(grubconfig, &grubConfigType);
3708      if (!gconfig)      if (!gconfig)
3709   grc = 1;   grc = 1;
3710      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3719  int main(int argc, const char ** argv) {
3719   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3720   }   }
3721    
3722   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3723        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3724        if (!lconfig)
3725     erc = 1;
3726        else
3727     erc = checkForExtLinux(lconfig);
3728     }
3729    
3730     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3731    
3732   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3733     if (gr2c == 2) printf("grub2\n");
3734   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3735     if (erc == 2) printf("extlinux\n");
3736    
3737   return 0;   return 0;
3738      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3750  int main(int argc, const char ** argv) {
3750   if (!entry) return 0;   if (!entry) return 0;
3751   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3752    
3753   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3754   if (!line) return 0;   if (!line) return 0;
3755    
3756          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3758  int main(int argc, const char ** argv) {
3758                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3759    
3760   return 0;   return 0;
3761    
3762        } else if (displayDefaultTitle) {
3763     struct singleLine * line;
3764     struct singleEntry * entry;
3765    
3766     if (config->defaultImage == -1) return 0;
3767     entry = findEntryByIndex(config, config->defaultImage);
3768     if (!entry) return 0;
3769    
3770     if (!configureGrub2) {
3771      line = getLineByType(LT_TITLE, entry->lines);
3772      if (!line) return 0;
3773      printf("%s\n", line->elements[1].item);
3774    
3775     } else {
3776      char * title;
3777    
3778      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3779      line = getLineByType(LT_MENUENTRY, entry->lines);
3780      if (!line) return 0;
3781      title = grub2ExtractTitle(line);
3782      if (title)
3783        printf("%s\n", title);
3784     }
3785     return 0;
3786    
3787        } else if (displayDefaultIndex) {
3788            if (config->defaultImage == -1) return 0;
3789            printf("%i\n", config->defaultImage);
3790    
3791      } else if (kernelInfo)      } else if (kernelInfo)
3792   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3793    
# Line 2585  int main(int argc, const char ** argv) { Line 3803  int main(int argc, const char ** argv) {
3803      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3804      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3805                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3806        if (updateKernelPath && newKernelInitrd) {
3807                if (updateInitrd(config, updateKernelPath, bootPrefix,
3808                                 newKernelInitrd)) return 1;
3809        }
3810      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3811                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3812                         extraInitrds, extraInitrdCount,
3813                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3814            
3815    
# Line 2597  int main(int argc, const char ** argv) { Line 3820  int main(int argc, const char ** argv) {
3820      }      }
3821    
3822      if (!outputFile)      if (!outputFile)
3823   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3824    
3825      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3826  }  }

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