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

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