Magellan Linux

Diff of /tags/grubby-8_32/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 1844 by niro, Mon Jul 2 12:59:07 2012 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39    #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43  #include "mount_by_label.h"  #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49    int debug = 0; /* Currently just for template debugging */
50    
51  #define _(A) (A)  #define _(A) (A)
52    
53    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
54  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
55    
56    #define NOOP_OPCODE 0x90
57    #define JMP_SHORT_OPCODE 0xeb
58    
59  /* comments get lumped in with indention */  /* comments get lumped in with indention */
60  struct lineElement {  struct lineElement {
61      char * item;      char * item;
62      char * indent;      char * indent;
63  };  };
64    
65  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
66         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
67         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
68        LT_KERNEL       = 1 << 2,
69        LT_INITRD       = 1 << 3,
70        LT_HYPER        = 1 << 4,
71        LT_DEFAULT      = 1 << 5,
72        LT_MBMODULE     = 1 << 6,
73        LT_ROOT         = 1 << 7,
74        LT_FALLBACK     = 1 << 8,
75        LT_KERNELARGS   = 1 << 9,
76        LT_BOOT         = 1 << 10,
77        LT_BOOTROOT     = 1 << 11,
78        LT_LBA          = 1 << 12,
79        LT_OTHER        = 1 << 13,
80        LT_GENERIC      = 1 << 14,
81        LT_ECHO    = 1 << 16,
82        LT_MENUENTRY    = 1 << 17,
83        LT_ENTRY_END    = 1 << 18,
84        LT_SET_VARIABLE = 1 << 19,
85        LT_UNKNOWN      = 1 << 20,
86    };
87    
88  struct singleLine {  struct singleLine {
89      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 104  struct singleEntry {
104    
105  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */
106    
107  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
108  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
109  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
110  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
111  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
112    #define NEED_MB      (1 << 4)
113    #define NEED_END     (1 << 5)
114    
115  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
116  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
117    #define DEFAULT_SAVED_GRUB2 -3
118    
119  struct keywordTypes {  struct keywordTypes {
120      char * key;      char * key;
121      enum lineType_e type;      enum lineType_e type;
122      char nextChar;      char nextChar;
123  } ;      char separatorChar;
124    };
125    
126    struct configFileInfo;
127    
128    typedef const char *(*findConfigFunc)(struct configFileInfo *);
129    typedef const int (*writeLineFunc)(struct configFileInfo *,
130     struct singleLine *line);
131    
132  struct configFileInfo {  struct configFileInfo {
133      char * defaultConfig;      char * defaultConfig;
134        findConfigFunc findConfig;
135        writeLineFunc writeLine;
136      struct keywordTypes * keywords;      struct keywordTypes * keywords;
137      int defaultIsIndex;      int defaultIsIndex;
138        int defaultIsVariable;
139      int defaultSupportSaved;      int defaultSupportSaved;
140      enum lineType_e entrySeparator;      enum lineType_e entryStart;
141        enum lineType_e entryEnd;
142      int needsBootPrefix;      int needsBootPrefix;
143      int argsInQuotes;      int argsInQuotes;
144      int maxTitleLength;      int maxTitleLength;
145      int titleBracketed;      int titleBracketed;
146        int titlePosition;
147        int mbHyperFirst;
148        int mbInitRdIsModule;
149        int mbConcatArgs;
150        int mbAllowExtraInitRds;
151  };  };
152    
153  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 156  struct keywordTypes grubKeywords[] = {
156      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
157      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
158      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
159      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
160      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
161        { "kernel",     LT_HYPER,       ' ' },
162      { NULL,    0, 0 },      { NULL,    0, 0 },
163  };  };
164    
165    const char *grubFindConfig(struct configFileInfo *cfi) {
166        static const char *configFiles[] = {
167     "/etc/grub.conf",
168     "/boot/grub/grub.conf",
169     "/boot/grub/menu.lst",
170     NULL
171        };
172        static int i = -1;
173    
174        if (i == -1) {
175     for (i = 0; configFiles[i] != NULL; i++) {
176        dbgPrintf("Checking \"%s\": ", configFiles[i]);
177        if (!access(configFiles[i], R_OK)) {
178     dbgPrintf("found\n");
179     return configFiles[i];
180        }
181        dbgPrintf("not found\n");
182     }
183        }
184        return configFiles[i];
185    }
186    
187  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
188      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
189      grubKeywords,    /* keywords */      .keywords = grubKeywords,
190      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
191      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
192      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
193      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
194      0,    /* argsInQuotes */      .mbHyperFirst = 1,
195      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
196      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
197    };
198    
199    struct keywordTypes grub2Keywords[] = {
200        { "menuentry",  LT_MENUENTRY,   ' ' },
201        { "}",          LT_ENTRY_END,   ' ' },
202        { "echo",       LT_ECHO,        ' ' },
203        { "set",        LT_SET_VARIABLE,' ', '=' },
204        { "root",       LT_BOOTROOT,    ' ' },
205        { "default",    LT_DEFAULT,     ' ' },
206        { "fallback",   LT_FALLBACK,    ' ' },
207        { "linux",      LT_KERNEL,      ' ' },
208        { "initrd",     LT_INITRD,      ' ', ' ' },
209        { "module",     LT_MBMODULE,    ' ' },
210        { "kernel",     LT_HYPER,       ' ' },
211        { NULL, 0, 0 },
212    };
213    
214    const char *grub2FindConfig(struct configFileInfo *cfi) {
215        static const char *configFiles[] = {
216     "/boot/grub/grub-efi.cfg",
217     "/boot/grub/grub.cfg",
218     NULL
219        };
220        static int i = -1;
221        static const char *grub_cfg = "/boot/grub/grub.cfg";
222    
223        if (i == -1) {
224     for (i = 0; configFiles[i] != NULL; i++) {
225        dbgPrintf("Checking \"%s\": ", configFiles[i]);
226        if (!access(configFiles[i], R_OK)) {
227     dbgPrintf("found\n");
228     return configFiles[i];
229        }
230     }
231        }
232    
233        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
234         * that isn't in grub1, and if it exists, return the config file path
235         * that they use. */
236        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
237     dbgPrintf("found\n");
238     return grub_cfg;
239        }
240    
241        dbgPrintf("not found\n");
242        return configFiles[i];
243    }
244    
245    int sizeOfSingleLine(struct singleLine * line) {
246      int i;
247      int count = 0;
248    
249      for (i = 0; i < line->numElements; i++) {
250        int indentSize = 0;
251    
252        count = count + strlen(line->elements[i].item);
253    
254        indentSize = strlen(line->elements[i].indent);
255        if (indentSize > 0)
256          count = count + indentSize;
257        else
258          /* be extra safe and add room for whitespaces */
259          count = count + 1;
260      }
261    
262      /* room for trailing terminator */
263      count = count + 1;
264    
265      return count;
266    }
267    
268    static int isquote(char q)
269    {
270        if (q == '\'' || q == '\"')
271     return 1;
272        return 0;
273    }
274    
275    char *grub2ExtractTitle(struct singleLine * line) {
276        char * current;
277        char * current_indent;
278        int current_len;
279        int current_indent_len;
280        int i;
281    
282        /* bail out if line does not start with menuentry */
283        if (strcmp(line->elements[0].item, "menuentry"))
284          return NULL;
285    
286        i = 1;
287        current = line->elements[i].item;
288        current_len = strlen(current);
289    
290        /* if second word is quoted, strip the quotes and return single word */
291        if (isquote(*current) && isquote(current[current_len - 1])) {
292     char *tmp;
293    
294     tmp = strdup(current);
295     *(tmp + current_len - 1) = '\0';
296     return ++tmp;
297        }
298    
299        /* if no quotes, return second word verbatim */
300        if (!isquote(*current))
301     return current;
302    
303        /* second element start with a quote, so we have to find the element
304         * whose last character is also quote (assuming it's the closing one) */
305        int resultMaxSize;
306        char * result;
307        
308        resultMaxSize = sizeOfSingleLine(line);
309        result = malloc(resultMaxSize);
310        snprintf(result, resultMaxSize, "%s", ++current);
311        
312        i++;
313        for (; i < line->numElements; ++i) {
314     current = line->elements[i].item;
315     current_len = strlen(current);
316     current_indent = line->elements[i].indent;
317     current_indent_len = strlen(current_indent);
318    
319     strncat(result, current_indent, current_indent_len);
320     if (!isquote(current[current_len-1])) {
321        strncat(result, current, current_len);
322     } else {
323        strncat(result, current, current_len - 1);
324        break;
325     }
326        }
327        return result;
328    }
329    
330    struct configFileInfo grub2ConfigType = {
331        .findConfig = grub2FindConfig,
332        .keywords = grub2Keywords,
333        .defaultIsIndex = 1,
334        .defaultSupportSaved = 1,
335        .defaultIsVariable = 1,
336        .entryStart = LT_MENUENTRY,
337        .entryEnd = LT_ENTRY_END,
338        .titlePosition = 1,
339        .needsBootPrefix = 1,
340        .mbHyperFirst = 1,
341        .mbInitRdIsModule = 1,
342        .mbAllowExtraInitRds = 1,
343  };  };
344    
345  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 373  struct keywordTypes yabootKeywords[] = {
373      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
374      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
375      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
376      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
377      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
378      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
379      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 393  struct keywordTypes liloKeywords[] = {
393      { NULL,    0, 0 },      { NULL,    0, 0 },
394  };  };
395    
396    struct keywordTypes eliloKeywords[] = {
397        { "label",    LT_TITLE,    '=' },
398        { "root",    LT_ROOT,    '=' },
399        { "default",    LT_DEFAULT,    '=' },
400        { "image",    LT_KERNEL,    '=' },
401        { "initrd",    LT_INITRD,    '=' },
402        { "append",    LT_KERNELARGS,  '=' },
403        { "vmm",    LT_HYPER,       '=' },
404        { NULL,    0, 0 },
405    };
406    
407  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
408      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
409      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 425  struct keywordTypes ziplKeywords[] = {
425      { NULL,         0, 0 },      { NULL,         0, 0 },
426  };  };
427    
428    struct keywordTypes extlinuxKeywords[] = {
429        { "label",    LT_TITLE,    ' ' },
430        { "root",    LT_ROOT,    ' ' },
431        { "default",    LT_DEFAULT,    ' ' },
432        { "kernel",    LT_KERNEL,    ' ' },
433        { "initrd",    LT_INITRD,      ' ', ',' },
434        { "append",    LT_KERNELARGS,  ' ' },
435        { "prompt",     LT_UNKNOWN,     ' ' },
436        { NULL,    0, 0 },
437    };
438    int useextlinuxmenu;
439  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
440      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
441      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
442      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
443      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
444      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
445      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
446  };  };
447    
448  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
449      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
450      liloKeywords,    /* keywords */      .keywords = liloKeywords,
451      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
452      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
453      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
454  };  };
455    
456  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
457      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
458      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
459      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
460      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
461      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
462      1,    /* needsBootPrefix */      .maxTitleLength = 15,
463      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
464  };  };
465    
466  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
467      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
468      siloKeywords,    /* keywords */      .keywords = siloKeywords,
469      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
470      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
471      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
472      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
473  };  };
474    
475  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
476      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
477      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
478      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
479      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
480      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
481      0,    /* needsBootPrefix */  };
482      1,    /* argsInQuotes */  
483      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
484      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
485        .keywords = extlinuxKeywords,
486        .entryStart = LT_TITLE,
487        .needsBootPrefix = 1,
488        .maxTitleLength = 255,
489        .mbAllowExtraInitRds = 1,
490  };  };
491    
492  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 501  struct grubConfig {
501      struct configFileInfo * cfi;      struct configFileInfo * cfi;
502  };  };
503    
504    blkid_cache blkid;
505    
506  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
507  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
508       const char * path, const char * prefix,       const char * path, const char * prefix,
509       int * index);       int * index);
 static char * strndup(char * from, int len);  
510  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
511  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
512    struct singleLine * lineDup(struct singleLine * line);
513  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
514  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
515       struct configFileInfo * cfi);       struct configFileInfo * cfi);
516  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
517         struct configFileInfo * cfi);         struct configFileInfo * cfi);
518  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
519    static void requote(struct singleLine *line, struct configFileInfo * cfi);
520  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
521      char * to;    const char * item, int insertHere,
522      struct configFileInfo * cfi);
523      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
524      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
525      to[len] = '\0';        struct configFileInfo * cfi);
526    static enum lineType_e getTypeByKeyword(char * keyword,
527      return to;   struct configFileInfo * cfi);
528  }  static struct singleLine * getLineByType(enum lineType_e type,
529     struct singleLine * line);
530    static int checkForExtLinux(struct grubConfig * config);
531    struct singleLine * addLineTmpl(struct singleEntry * entry,
532                                    struct singleLine * tmplLine,
533                                    struct singleLine * prevLine,
534                                    const char * val,
535     struct configFileInfo * cfi);
536    struct singleLine *  addLine(struct singleEntry * entry,
537                                 struct configFileInfo * cfi,
538                                 enum lineType_e type, char * defaultIndent,
539                                 const char * val);
540    
541  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
542  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 571  static char * sdupprintf(const char *for
571      return buf;      return buf;
572  }  }
573    
574    static struct keywordTypes * getKeywordByType(enum lineType_e type,
575          struct configFileInfo * cfi) {
576        struct keywordTypes * kw;
577        for (kw = cfi->keywords; kw->key; kw++) {
578     if (kw->type == type)
579        return kw;
580        }
581        return NULL;
582    }
583    
584    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
585        struct keywordTypes *kt = getKeywordByType(type, cfi);
586        if (kt)
587     return kt->key;
588        return "unknown";
589    }
590    
591    static char * getpathbyspec(char *device) {
592        if (!blkid)
593            blkid_get_cache(&blkid, NULL);
594    
595        return blkid_get_devname(blkid, device, NULL);
596    }
597    
598    static char * getuuidbydev(char *device) {
599        if (!blkid)
600     blkid_get_cache(&blkid, NULL);
601    
602        return blkid_get_tag_value(blkid, "UUID", device);
603    }
604    
605    static enum lineType_e getTypeByKeyword(char * keyword,
606     struct configFileInfo * cfi) {
607        struct keywordTypes * kw;
608        for (kw = cfi->keywords; kw->key; kw++) {
609     if (!strcmp(keyword, kw->key))
610        return kw->type;
611        }
612        return LT_UNKNOWN;
613    }
614    
615    static struct singleLine * getLineByType(enum lineType_e type,
616     struct singleLine * line) {
617        dbgPrintf("getLineByType(%d): ", type);
618        for (; line; line = line->next) {
619     dbgPrintf("%d:%s ", line->type,
620      line->numElements ? line->elements[0].item : "(empty)");
621     if (line->type & type) break;
622        }
623        dbgPrintf(line ? "\n" : " (failed)\n");
624        return line;
625    }
626    
627  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
628      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
629          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
630          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
631              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 637  static int isBracketedTitle(struct singl
637      return 0;      return 0;
638  }  }
639    
640  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
641                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
642      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
643   return 0;   (cfi->titleBracketed && isBracketedTitle(line));
     if (line->type == cfi->entrySeparator)  
         return 1;  
     if (line->type == LT_OTHER)  
         return 1;  
     if (cfi->titleBracketed && isBracketedTitle(line)) {  
         return 1;  
     }  
     return 0;  
644  }  }
645    
646  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 691  static void lineInit(struct singleLine *
691      line->next = NULL;      line->next = NULL;
692  }  }
693    
694    struct singleLine * lineDup(struct singleLine * line) {
695        int i;
696        struct singleLine * newLine = malloc(sizeof(*newLine));
697    
698        newLine->indent = strdup(line->indent);
699        newLine->next = NULL;
700        newLine->type = line->type;
701        newLine->numElements = line->numElements;
702        newLine->elements = malloc(sizeof(*newLine->elements) *
703           newLine->numElements);
704    
705        for (i = 0; i < newLine->numElements; i++) {
706     newLine->elements[i].indent = strdup(line->elements[i].indent);
707     newLine->elements[i].item = strdup(line->elements[i].item);
708        }
709    
710        return newLine;
711    }
712    
713  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
714      int i;      int i;
715    
# Line 410  static int lineWrite(FILE * out, struct Line 731  static int lineWrite(FILE * out, struct
731      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
732    
733      for (i = 0; i < line->numElements; i++) {      for (i = 0; i < line->numElements; i++) {
734     /* Need to handle this, because we strip the quotes from
735     * menuentry when read it. */
736     if (line->type == LT_MENUENTRY && i == 1) {
737        if(!isquote(*line->elements[i].item))
738     fprintf(out, "\'%s\'", line->elements[i].item);
739        else
740     fprintf(out, "%s", line->elements[i].item);
741        fprintf(out, "%s", line->elements[i].indent);
742    
743        continue;
744     }
745    
746   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
747      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
748    
749   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
750   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
751        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
752      }      }
753    
754      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 767  static int getNextLine(char ** bufPtr, s
767      char * chptr;      char * chptr;
768      int elementsAlloced = 0;      int elementsAlloced = 0;
769      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
770      int first = 1;      int first = 1;
     int i;  
771    
772      lineFree(line);      lineFree(line);
773    
# Line 489  static int getNextLine(char ** bufPtr, s Line 821  static int getNextLine(char ** bufPtr, s
821      if (!line->numElements)      if (!line->numElements)
822   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
823      else {      else {
824   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
825      if (!strcmp(line->elements[0].item, keywords[i].key)) break;   if (line->type == LT_UNKNOWN) {
   
  if (keywords[i].key) {  
     line->type = keywords[i].type;  
  } else {  
     line->type = LT_UNKNOWN;  
               
826              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
827               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
828              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 858  static int getNextLine(char ** bufPtr, s
858   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
859   line->numElements = 0;   line->numElements = 0;
860      }      }
861     } else {
862     struct keywordTypes *kw;
863    
864     kw = getKeywordByType(line->type, cfi);
865    
866     /* space isn't the only separator, we need to split
867     * elements up more
868     */
869     if (!isspace(kw->separatorChar)) {
870        int i;
871        char indent[2] = "";
872        indent[0] = kw->separatorChar;
873        for (i = 1; i < line->numElements; i++) {
874     char *p;
875     int j;
876     int numNewElements;
877    
878     numNewElements = 0;
879     p = line->elements[i].item;
880     while (*p != '\0') {
881     if (*p == kw->separatorChar)
882     numNewElements++;
883     p++;
884     }
885     if (line->numElements + numNewElements >= elementsAlloced) {
886     elementsAlloced += numNewElements + 5;
887     line->elements = realloc(line->elements,
888        sizeof(*line->elements) * elementsAlloced);
889     }
890    
891     for (j = line->numElements; j > i; j--) {
892     line->elements[j + numNewElements] = line->elements[j];
893     }
894     line->numElements += numNewElements;
895    
896     p = line->elements[i].item;
897     while (*p != '\0') {
898    
899     while (*p != kw->separatorChar && *p != '\0') p++;
900     if (*p == '\0') {
901     break;
902     }
903    
904     line->elements[i + 1].indent = line->elements[i].indent;
905     line->elements[i].indent = strdup(indent);
906     *p++ = '\0';
907     i++;
908     line->elements[i].item = strdup(p);
909     }
910        }
911     }
912   }   }
913      }      }
914    
# Line 595  static struct grubConfig * readConfig(co Line 972  static struct grubConfig * readConfig(co
972      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
973   }   }
974    
975   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
976      sawEntry = 1;      sawEntry = 1;
977      if (!entry) {      if (!entry) {
978   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 988  static struct grubConfig * readConfig(co
988      entry->next = NULL;      entry->next = NULL;
989   }   }
990    
991   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
992        int i;
993        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
994        dbgPrintf("%s", line->indent);
995        for (i = 0; i < line->numElements; i++)
996     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
997        dbgPrintf("\n");
998        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
999        if (kwType && line->numElements == 3 &&
1000        !strcmp(line->elements[1].item, kwType->key)) {
1001     dbgPrintf("Line sets default config\n");
1002     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1003     defaultLine = line;
1004        }
1005     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1006      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1007      defaultLine = line;      defaultLine = line;
1008    
1009            } else if (line->type == LT_KERNEL) {
1010        /* if by some freak chance this is multiboot and the "module"
1011         * lines came earlier in the template, make sure to use LT_HYPER
1012         * instead of LT_KERNEL now
1013         */
1014        if (entry->multiboot)
1015     line->type = LT_HYPER;
1016    
1017          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1018        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1019         * instead, now that we know this is a multiboot entry.
1020         * This only applies to grub, but that's the only place we
1021         * should find LT_MBMODULE lines anyway.
1022         */
1023        struct singleLine * l;
1024        for (l = entry->lines; l; l = l->next) {
1025     if (l->type == LT_HYPER)
1026        break;
1027     else if (l->type == LT_KERNEL) {
1028        l->type = LT_HYPER;
1029        break;
1030     }
1031        }
1032              entry->multiboot = 1;              entry->multiboot = 1;
1033    
1034     } else if (line->type == LT_HYPER) {
1035        entry->multiboot = 1;
1036    
1037   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1038      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1039      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1040    
1041   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1042      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1043      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 1062  static struct grubConfig * readConfig(co
1062      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1063      line->elements[1].item = buf;      line->elements[1].item = buf;
1064      line->numElements = 2;      line->numElements = 2;
1065     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1066        /* let --remove-kernel="TITLE=what" work */
1067        len = 0;
1068        char *extras;
1069        char *title;
1070    
1071        for (i = 1; i < line->numElements; i++) {
1072     len += strlen(line->elements[i].item);
1073     len += strlen(line->elements[i].indent);
1074        }
1075        buf = malloc(len + 1);
1076        *buf = '\0';
1077    
1078        /* allocate mem for extra flags. */
1079        extras = malloc(len + 1);
1080        *extras = '\0';
1081    
1082        /* get title. */
1083        for (i = 0; i < line->numElements; i++) {
1084     if (!strcmp(line->elements[i].item, "menuentry"))
1085        continue;
1086     if (isquote(*line->elements[i].item))
1087        title = line->elements[i].item + 1;
1088     else
1089        title = line->elements[i].item;
1090    
1091     len = strlen(title);
1092            if (isquote(title[len-1])) {
1093        strncat(buf, title,len-1);
1094        break;
1095     } else {
1096        strcat(buf, title);
1097        strcat(buf, line->elements[i].indent);
1098     }
1099        }
1100    
1101        /* get extras */
1102        int count = 0;
1103        for (i = 0; i < line->numElements; i++) {
1104     if (count >= 2) {
1105        strcat(extras, line->elements[i].item);
1106        strcat(extras, line->elements[i].indent);
1107     }
1108    
1109     if (!strcmp(line->elements[i].item, "menuentry"))
1110        continue;
1111    
1112     /* count ' or ", there should be two in menuentry line. */
1113     if (isquote(*line->elements[i].item))
1114        count++;
1115    
1116     len = strlen(line->elements[i].item);
1117    
1118     if (isquote(line->elements[i].item[len -1]))
1119        count++;
1120    
1121     /* ok, we get the final ' or ", others are extras. */
1122                }
1123        line->elements[1].indent =
1124     line->elements[line->numElements - 2].indent;
1125        line->elements[1].item = buf;
1126        line->elements[2].indent =
1127     line->elements[line->numElements - 2].indent;
1128        line->elements[2].item = extras;
1129        line->numElements = 3;
1130   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1131      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1132         on write. This is one of the few (the only?) places that grubby         on write. This is one of the few (the only?) places that grubby
# Line 651  static struct grubConfig * readConfig(co Line 1135  static struct grubConfig * readConfig(co
1135      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1136   int last, len;   int last, len;
1137    
1138   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1139      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1140     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1141    
1142   last = line->numElements - 1;   last = line->numElements - 1;
1143   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1144   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1145      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1146      }      }
   
1147   }   }
1148    
1149   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
# Line 680  static struct grubConfig * readConfig(co Line 1163  static struct grubConfig * readConfig(co
1163   movedLine = 1;   movedLine = 1;
1164   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1165   }   }
1166    
1167   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1168     which was moved, drop it. */     which was moved, drop it. */
1169   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {
# Line 695  static struct grubConfig * readConfig(co Line 1179  static struct grubConfig * readConfig(co
1179   entry->lines = line;   entry->lines = line;
1180      else      else
1181   last->next = line;   last->next = line;
1182        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1183    
1184        /* we could have seen this outside of an entry... if so, we
1185         * ignore it like any other line we don't grok */
1186        if (line->type == LT_ENTRY_END && sawEntry)
1187     sawEntry = 0;
1188   } else {   } else {
1189      if (!cfg->theLines)      if (!cfg->theLines)
1190   cfg->theLines = line;   cfg->theLines = line;
1191      else {      else
1192   last->next = line;   last->next = line;
1193      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1194   }   }
1195    
1196   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1198  static struct grubConfig * readConfig(co
1198    
1199      free(incoming);      free(incoming);
1200    
1201        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1202      if (defaultLine) {      if (defaultLine) {
1203   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1204        cfi->defaultSupportSaved &&
1205        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1206        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1207     } else if (cfi->defaultIsVariable) {
1208        char *value = defaultLine->elements[2].item;
1209        while (*value && (*value == '"' || *value == '\'' ||
1210        *value == ' ' || *value == '\t'))
1211     value++;
1212        cfg->defaultImage = strtol(value, &end, 10);
1213        while (*end && (*end == '"' || *end == '\'' ||
1214        *end == ' ' || *end == '\t'))
1215     end++;
1216        if (*end) cfg->defaultImage = -1;
1217     } else if (cfi->defaultSupportSaved &&
1218   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1219      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1220   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1235  static struct grubConfig * readConfig(co
1235                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1236                  }                  }
1237   i++;   i++;
1238     entry = NULL;
1239      }      }
1240    
1241      if (entry) cfg->defaultImage = i;      if (entry){
1242            cfg->defaultImage = i;
1243        }else{
1244            cfg->defaultImage = -1;
1245        }
1246   }   }
1247        } else {
1248            cfg->defaultImage = 0;
1249      }      }
1250    
1251      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1261  static void writeDefault(FILE * out, cha
1261    
1262      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1263   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1264        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1265     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1266      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1267   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1268      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1269      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1270     cfg->defaultImage);
1271        } else {
1272     fprintf(out, "%sdefault%s%d\n", indent, separator,
1273     cfg->defaultImage);
1274        }
1275   } else {   } else {
1276      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1277    
# Line 769  static void writeDefault(FILE * out, cha Line 1288  static void writeDefault(FILE * out, cha
1288    
1289      if (!entry) return;      if (!entry) return;
1290    
1291      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1292    
1293      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1294   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1322  static int writeConfig(struct grubConfig
1322      int rc;      int rc;
1323    
1324      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1325         directory to / */         directory to the dir of the symlink */
1326      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1327      do {      do {
1328   buf = alloca(len + 1);   buf = alloca(len + 1);
1329   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1330   if (rc == len) len += 256;   if (rc == len) len += 256;
1331      } while (rc == len);      } while (rc == len);
1332            
# Line 843  static int writeConfig(struct grubConfig Line 1361  static int writeConfig(struct grubConfig
1361      }      }
1362    
1363      line = cfg->theLines;      line = cfg->theLines;
1364        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1365      while (line) {      while (line) {
1366   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1367     line->numElements == 3 &&
1368     !strcmp(line->elements[1].item, defaultKw->key)) {
1369        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1370        needs &= ~MAIN_DEFAULT;
1371     } else if (line->type == LT_DEFAULT) {
1372      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1373      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1374   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1436  static int numEntries(struct grubConfig
1436      return i;      return i;
1437  }  }
1438    
1439    static char *findDiskForRoot()
1440    {
1441        int fd;
1442        char buf[65536];
1443        char *devname;
1444        char *chptr;
1445        int rc;
1446    
1447        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1448            fprintf(stderr, "grubby: failed to open %s: %s\n",
1449                    _PATH_MOUNTED, strerror(errno));
1450            return NULL;
1451        }
1452    
1453        rc = read(fd, buf, sizeof(buf) - 1);
1454        if (rc <= 0) {
1455            fprintf(stderr, "grubby: failed to read %s: %s\n",
1456                    _PATH_MOUNTED, strerror(errno));
1457            close(fd);
1458            return NULL;
1459        }
1460        close(fd);
1461        buf[rc] = '\0';
1462        chptr = buf;
1463    
1464        char *foundanswer = NULL;
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                /* remember the last / entry in mtab */
1494               foundanswer = devname;
1495            }
1496    
1497            /* Next line */
1498            chptr = strchr(chptr, '\n');
1499            if (chptr)
1500                chptr++;
1501        }
1502    
1503        /* Return the last / entry found */
1504        if (foundanswer) {
1505            chptr = strchr(foundanswer, ' ');
1506            *chptr = '\0';
1507            return strdup(foundanswer);
1508        }
1509    
1510        return NULL;
1511    }
1512    
1513    void printEntry(struct singleEntry * entry) {
1514        int i;
1515        struct singleLine * line;
1516    
1517        for (line = entry->lines; line; line = line->next) {
1518     fprintf(stderr, "DBG: %s", line->indent);
1519     for (i = 0; i < line->numElements; i++) {
1520        /* Need to handle this, because we strip the quotes from
1521         * menuentry when read it. */
1522        if (line->type == LT_MENUENTRY && i == 1) {
1523     if(!isquote(*line->elements[i].item))
1524        fprintf(stderr, "\'%s\'", line->elements[i].item);
1525     else
1526        fprintf(stderr, "%s", line->elements[i].item);
1527     fprintf(stderr, "%s", line->elements[i].indent);
1528    
1529     continue;
1530        }
1531        
1532        fprintf(stderr, "%s%s",
1533        line->elements[i].item, line->elements[i].indent);
1534     }
1535     fprintf(stderr, "\n");
1536        }
1537    }
1538    
1539    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1540    {
1541        va_list argp;
1542    
1543        if (!debug)
1544     return;
1545    
1546        va_start(argp, fmt);
1547        fprintf(stderr, "DBG: Image entry failed: ");
1548        vfprintf(stderr, fmt, argp);
1549        printEntry(entry);
1550        va_end(argp);
1551    }
1552    
1553    #define beginswith(s, c) ((s) && (s)[0] == (c))
1554    
1555    static int endswith(const char *s, char c)
1556    {
1557     int slen;
1558    
1559     if (!s || !s[0])
1560     return 0;
1561     slen = strlen(s) - 1;
1562    
1563     return s[slen] == c;
1564    }
1565    
1566  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1567    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1568      struct singleLine * line;      struct singleLine * line;
1569      char * fullName;      char * fullName;
1570      int i;      int i;
     struct stat sb, sb2;  
1571      char * dev;      char * dev;
     char * end;  
1572      char * rootspec;      char * rootspec;
1573        char * rootdev;
1574    
1575      line = entry->lines;      if (skipRemoved && entry->skip) {
1576      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1577         return 0;
1578      if (!line) return 0;      }
1579      if (skipRemoved && entry->skip) return 0;  
1580      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1581        if (!line) {
1582     notSuitablePrintf(entry, "no line found\n");
1583     return 0;
1584        }
1585        if (line->numElements < 2) {
1586     notSuitablePrintf(entry, "line has only %d elements\n",
1587        line->numElements);
1588     return 0;
1589        }
1590    
1591      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1592    
1593      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1594        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1595      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1596      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1597              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1598                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1599      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1600                line->elements[1].item + rootspec_offset);
1601        if (access(fullName, R_OK)) {
1602     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1603     return 0;
1604        }
1605      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1606   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1607      if (i < line->numElements) {      if (i < line->numElements) {
1608   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1609      } else {      } else {
1610   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1611   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1612    
1613   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1614      dev = line->elements[1].item;      dev = line->elements[1].item;
1615   } else {   } else {
1616              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1617      /* 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.
1618      line = entry->lines;       */
1619        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1620    
1621              /* failed to find one */              /* failed to find one */
1622              if (!line) return 0;              if (!line) {
1623     notSuitablePrintf(entry, "no line found\n");
1624     return 0;
1625                }
1626    
1627      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1628          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1629      if (i < line->numElements)      if (i < line->numElements)
1630          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1631      else {      else {
1632     notSuitablePrintf(entry, "no root= entry found\n");
1633   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1634          return 0;          return 0;
1635              }              }
1636   }   }
1637      }      }
1638    
1639      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1640   dev += 6;      if (!getpathbyspec(dev)) {
1641            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1642   /* check which device has this label */          return 0;
1643   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1644   if (!dev) return 0;   dev = getpathbyspec(dev);
1645    
1646        rootdev = findDiskForRoot();
1647        if (!rootdev) {
1648            notSuitablePrintf(entry, "can't find root device\n");
1649     return 0;
1650      }      }
1651    
1652      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1653   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1654      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1655      } else {          free(rootdev);
1656   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1657   if (*end) return 0;      }
1658    
1659        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1660            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1661     getuuidbydev(rootdev), getuuidbydev(dev));
1662     free(rootdev);
1663            return 0;
1664      }      }
     stat("/", &sb2);  
1665    
1666      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1667    
1668      return 1;      return 1;
1669  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1707  struct singleEntry * findEntryByPath(str
1707   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1708   if (!entry) return NULL;   if (!entry) return NULL;
1709    
1710   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1711   if (!line) return NULL;   if (!line) return NULL;
1712    
1713   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1745  struct singleEntry * findEntryByPath(str
1745    
1746   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1747      prefix = "";      prefix = "";
1748      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1749      kernel += 6;      kernel += 6;
1750   }   }
1751    
1752   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1753      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1754    
1755        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1756    
1757      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1758                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1759          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1760                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1761                              kernel + strlen(prefix)))       checkType, line);
1762                      break;   if (!line) break;  /* not found in this entry */
1763              }  
1764                 if (line && line->type != LT_MENUENTRY &&
1765              /* have to check multiboot lines too */   line->numElements >= 2) {
1766              if (entry->multiboot) {      rootspec = getRootSpecifier(line->elements[1].item);
1767                  while (line && line->type != LT_MBMODULE) line = line->next;      if (!strcmp(line->elements[1].item +
1768                  if (line && line->numElements >= 2 && !entry->skip) {   ((rootspec != NULL) ? strlen(rootspec) : 0),
1769                      rootspec = getRootSpecifier(line->elements[1].item);   kernel + strlen(prefix)))
1770                      if (!strcmp(line->elements[1].item  +   break;
1771                                  ((rootspec != NULL) ? strlen(rootspec) : 0),   }
1772                                  kernel + strlen(prefix)))   if(line->type == LT_MENUENTRY &&
1773                          break;   !strcmp(line->elements[1].item, kernel))
1774                  }      break;
1775              }      }
1776    
1777      i++;      /* make sure this entry has a kernel identifier; this skips
1778         * non-Linux boot entries (could find netbsd etc, though, which is
1779         * unfortunate)
1780         */
1781        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1782     break; /* found 'im! */
1783   }   }
1784    
1785   if (index) *index = i;   if (index) *index = i;
1786      }      }
1787    
1788      if (!entry) return NULL;      return entry;
1789    }
     /* 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);  
     }  
   
     return entry;  
 }  
1790    
1791  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
1792      struct singleEntry * entry;      struct singleEntry * entry;
# Line 1200  void markRemovedImage(struct grubConfig Line 1863  void markRemovedImage(struct grubConfig
1863        const char * prefix) {        const char * prefix) {
1864      struct singleEntry * entry;      struct singleEntry * entry;
1865    
1866      if (!image) return;      if (!image)
1867     return;
1868    
1869        /* check and see if we're removing the default image */
1870        if (isdigit(*image)) {
1871     entry = findEntryByPath(cfg, image, prefix, NULL);
1872     if(entry)
1873        entry->skip = 1;
1874     return;
1875        }
1876    
1877      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1878   entry->skip = 1;   entry->skip = 1;
# Line 1227  void setDefaultImage(struct grubConfig * Line 1899  void setDefaultImage(struct grubConfig *
1899    
1900      /* 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
1901         changes */         changes */
1902      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1903     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1904        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1905        return;        return;
1906    
# Line 1286  void displayEntry(struct singleEntry * e Line 1959  void displayEntry(struct singleEntry * e
1959      char * root = NULL;      char * root = NULL;
1960      int i;      int i;
1961    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1962      printf("index=%d\n", index);      printf("index=%d\n", index);
1963    
1964      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1965        if (!line) {
1966            printf("non linux entry\n");
1967            return;
1968        }
1969    
1970        printf("kernel=%s%s\n", prefix, line->elements[1].item);
1971    
1972      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1973   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1984  void displayEntry(struct singleEntry * e
1984   }   }
1985   printf("\"\n");   printf("\"\n");
1986      } else {      } else {
1987   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1988   if (line) {   if (line) {
1989      char * s;      char * s;
1990    
# Line 1334  void displayEntry(struct singleEntry * e Line 2008  void displayEntry(struct singleEntry * e
2008      }      }
2009    
2010      if (!root) {      if (!root) {
2011   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2012   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2013      root=line->elements[1].item;      root=line->elements[1].item;
2014      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2023  void displayEntry(struct singleEntry * e
2023   printf("root=%s\n", s);   printf("root=%s\n", s);
2024      }      }
2025    
2026      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2027    
2028      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2029   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1360  void displayEntry(struct singleEntry * e Line 2031  void displayEntry(struct singleEntry * e
2031      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2032   printf("\n");   printf("\n");
2033      }      }
2034    
2035        line = getLineByType(LT_TITLE, entry->lines);
2036        if (line) {
2037     printf("title=%s\n", line->elements[1].item);
2038        } else {
2039     char * title;
2040     line = getLineByType(LT_MENUENTRY, entry->lines);
2041     title = grub2ExtractTitle(line);
2042     if (title)
2043        printf("title=%s\n", title);
2044        }
2045  }  }
2046    
2047  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2051  int parseSysconfigGrub(int * lbaPtr, cha
2051      char * start;      char * start;
2052      char * param;      char * param;
2053    
2054      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2055      if (!in) return 1;      if (!in) return 1;
2056    
2057      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 2113  int displayInfo(struct grubConfig * conf
2113   return 1;   return 1;
2114      }      }
2115    
2116      /* 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
2117         be a better way */         be a better way */
2118      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2119   dumpSysconfigGrub();   dumpSysconfigGrub();
2120      } else {      } else {
2121   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2122   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2123      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2124   }   }
2125    
2126   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2127   if (line) printf("lba\n");   if (line) printf("lba\n");
2128      }      }
2129    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2138  int displayInfo(struct grubConfig * conf
2138      return 0;      return 0;
2139  }  }
2140    
2141    struct singleLine * addLineTmpl(struct singleEntry * entry,
2142     struct singleLine * tmplLine,
2143     struct singleLine * prevLine,
2144     const char * val,
2145     struct configFileInfo * cfi)
2146    {
2147        struct singleLine * newLine = lineDup(tmplLine);
2148    
2149        if (val) {
2150     /* override the inherited value with our own.
2151     * This is a little weak because it only applies to elements[1]
2152     */
2153     if (newLine->numElements > 1)
2154        removeElement(newLine, 1);
2155     insertElement(newLine, val, 1, cfi);
2156    
2157     /* but try to keep the rootspec from the template... sigh */
2158     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2159        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2160        if (rootspec != NULL) {
2161     free(newLine->elements[1].item);
2162     newLine->elements[1].item =
2163        sdupprintf("%s%s", rootspec, val);
2164        }
2165     }
2166        }
2167    
2168        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2169          newLine->elements[0].item : "");
2170    
2171        if (!entry->lines) {
2172     /* first one on the list */
2173     entry->lines = newLine;
2174        } else if (prevLine) {
2175     /* add after prevLine */
2176     newLine->next = prevLine->next;
2177     prevLine->next = newLine;
2178        }
2179    
2180        return newLine;
2181    }
2182    
2183  /* val may be NULL */  /* val may be NULL */
2184  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2185       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2186       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2187       char * val) {       const char * val) {
2188      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2189      int i;      struct keywordTypes * kw;
2190        struct singleLine tmpl;
2191    
2192      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2193   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2194      if (type != LT_TITLE || !cfi->titleBracketed)       */
2195          if (!cfi->keywords[i].key) abort();  
2196        if (type == LT_TITLE && cfi->titleBracketed) {
2197     /* we're doing a bracketed title (zipl) */
2198     tmpl.type = type;
2199     tmpl.numElements = 1;
2200     tmpl.elements = alloca(sizeof(*tmpl.elements));
2201     tmpl.elements[0].item = alloca(strlen(val)+3);
2202     sprintf(tmpl.elements[0].item, "[%s]", val);
2203     tmpl.elements[0].indent = "";
2204     val = NULL;
2205        } else if (type == LT_MENUENTRY) {
2206     char *lineend = "--class gnu-linux --class gnu --class os {";
2207     if (!val) {
2208        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2209        abort();
2210     }
2211     kw = getKeywordByType(type, cfi);
2212     if (!kw) {
2213        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2214        abort();
2215     }
2216     tmpl.indent = "";
2217     tmpl.type = type;
2218     tmpl.numElements = 3;
2219     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2220     tmpl.elements[0].item = kw->key;
2221     tmpl.elements[0].indent = alloca(2);
2222     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2223     tmpl.elements[1].item = (char *)val;
2224     tmpl.elements[1].indent = alloca(2);
2225     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2226     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2227     strcpy(tmpl.elements[2].item, lineend);
2228     tmpl.elements[2].indent = "";
2229        } else {
2230     kw = getKeywordByType(type, cfi);
2231     if (!kw) {
2232        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2233        abort();
2234     }
2235     tmpl.type = type;
2236     tmpl.numElements = val ? 2 : 1;
2237     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2238     tmpl.elements[0].item = kw->key;
2239     tmpl.elements[0].indent = alloca(2);
2240     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2241     if (val) {
2242        tmpl.elements[1].item = (char *)val;
2243        tmpl.elements[1].indent = "";
2244     }
2245        }
2246    
2247      /* 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
2248         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2249         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
2250         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2251         differently from the rest) */         differently from the rest) */
2252      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2253   line = entry->lines;   if (line->numElements) prev = line;
2254   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2255   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;  
2256      }      }
2257    
2258      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2259          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2260          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2261          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2262          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2263          line->elements[0].indent = malloc(2);   else
2264          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2265          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2266             if (menuEntry)
2267          if (val) {      tmpl.indent = "\t";
2268              line->elements[1].item = val;   else if (prev == entry->lines)
2269              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2270          }   else
2271      } 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("");  
2272      }      }
2273    
2274      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2275  }  }
2276    
2277  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2296  void removeLine(struct singleEntry * ent
2296      free(line);      free(line);
2297  }  }
2298    
2299    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2300    {
2301        struct singleLine newLine = {
2302     .indent = tmplLine->indent,
2303     .type = tmplLine->type,
2304     .next = tmplLine->next,
2305        };
2306        int firstQuotedItem = -1;
2307        int quoteLen = 0;
2308        int j;
2309        int element = 0;
2310        char *c;
2311    
2312        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2313        strcpy(c, tmplLine->elements[0].item);
2314        insertElement(&newLine, c, element++, cfi);
2315        free(c);
2316        c = NULL;
2317    
2318        for (j = 1; j < tmplLine->numElements; j++) {
2319     if (firstQuotedItem == -1) {
2320        quoteLen += strlen(tmplLine->elements[j].item);
2321        
2322        if (isquote(tmplLine->elements[j].item[0])) {
2323     firstQuotedItem = j;
2324            quoteLen += strlen(tmplLine->elements[j].indent);
2325        } else {
2326     c = malloc(quoteLen + 1);
2327     strcpy(c, tmplLine->elements[j].item);
2328     insertElement(&newLine, c, element++, cfi);
2329     free(c);
2330     quoteLen = 0;
2331        }
2332     } else {
2333        int itemlen = strlen(tmplLine->elements[j].item);
2334        quoteLen += itemlen;
2335        quoteLen += strlen(tmplLine->elements[j].indent);
2336        
2337        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2338     c = malloc(quoteLen + 1);
2339     c[0] = '\0';
2340     for (int i = firstQuotedItem; i < j+1; i++) {
2341        strcat(c, tmplLine->elements[i].item);
2342        strcat(c, tmplLine->elements[i].indent);
2343     }
2344     insertElement(&newLine, c, element++, cfi);
2345     free(c);
2346    
2347     firstQuotedItem = -1;
2348     quoteLen = 0;
2349        }
2350     }
2351        }
2352        while (tmplLine->numElements)
2353     removeElement(tmplLine, 0);
2354        if (tmplLine->elements)
2355     free(tmplLine->elements);
2356    
2357        tmplLine->numElements = newLine.numElements;
2358        tmplLine->elements = newLine.elements;
2359    }
2360    
2361    static void insertElement(struct singleLine * line,
2362      const char * item, int insertHere,
2363      struct configFileInfo * cfi)
2364    {
2365        struct keywordTypes * kw;
2366        char indent[2] = "";
2367    
2368        /* sanity check */
2369        if (insertHere > line->numElements) {
2370     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2371      insertHere, line->numElements);
2372     insertHere = line->numElements;
2373        }
2374    
2375        line->elements = realloc(line->elements, (line->numElements + 1) *
2376         sizeof(*line->elements));
2377        memmove(&line->elements[insertHere+1],
2378        &line->elements[insertHere],
2379        (line->numElements - insertHere) *
2380        sizeof(*line->elements));
2381        line->elements[insertHere].item = strdup(item);
2382    
2383        kw = getKeywordByType(line->type, cfi);
2384    
2385        if (line->numElements == 0) {
2386     indent[0] = '\0';
2387        } else if (insertHere == 0) {
2388     indent[0] = kw->nextChar;
2389        } else if (kw->separatorChar != '\0') {
2390     indent[0] = kw->separatorChar;
2391        } else {
2392     indent[0] = ' ';
2393        }
2394    
2395        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2396     /* move the end-of-line forward */
2397     line->elements[insertHere].indent =
2398        line->elements[insertHere-1].indent;
2399     line->elements[insertHere-1].indent = strdup(indent);
2400        } else {
2401     line->elements[insertHere].indent = strdup(indent);
2402        }
2403    
2404        line->numElements++;
2405    
2406        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2407          line->elements[0].item,
2408          line->elements[insertHere].item,
2409          line->elements[insertHere].indent,
2410          insertHere);
2411    }
2412    
2413    static void removeElement(struct singleLine * line, int removeHere) {
2414        int i;
2415    
2416        /* sanity check */
2417        if (removeHere >= line->numElements) return;
2418    
2419        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2420          removeHere, line->elements[removeHere].item);
2421    
2422        free(line->elements[removeHere].item);
2423    
2424        if (removeHere > 1) {
2425     /* previous argument gets this argument's post-indentation */
2426     free(line->elements[removeHere-1].indent);
2427     line->elements[removeHere-1].indent =
2428        line->elements[removeHere].indent;
2429        } else {
2430     free(line->elements[removeHere].indent);
2431        }
2432    
2433        /* now collapse the array, but don't bother to realloc smaller */
2434        for (i = removeHere; i < line->numElements - 1; i++)
2435     line->elements[i] = line->elements[i + 1];
2436    
2437        line->numElements--;
2438    }
2439    
2440  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2441      char * first, * second;      char * first, * second;
2442      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2459  int updateActualImage(struct grubConfig
2459      struct singleEntry * entry;      struct singleEntry * entry;
2460      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2461      int index = 0;      int index = 0;
2462      int i, j, k;      int i, k;
2463      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2464      const char ** arg;      const char ** arg;
2465      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2466      int firstElement;      int firstElement;
2467      int *usedElements, *usedArgs;      int *usedElements;
2468        int doreplace;
2469    
2470      if (!image) return 0;      if (!image) return 0;
2471    
# Line 1609  int updateActualImage(struct grubConfig Line 2492  int updateActualImage(struct grubConfig
2492   }   }
2493      }      }
2494    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2495    
2496      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2497   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2498    
2499      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2500   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2501    
2502      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2503    
2504      k = 0;   if (multibootArgs && !entry->multiboot)
2505      for (arg = newArgs; *arg; arg++)      continue;
2506          k++;  
2507      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2508     * LT_KERNELARGS, use that.  Otherwise use
2509     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2510     */
2511     if (useKernelArgs) {
2512        line = getLineByType(LT_KERNELARGS, entry->lines);
2513        if (!line) {
2514     /* no LT_KERNELARGS, need to add it */
2515     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2516           cfg->secondaryIndent, NULL);
2517        }
2518        firstElement = 1;
2519    
2520      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2521   index++;      line = getLineByType(LT_HYPER, entry->lines);
2522        if (!line) {
2523     /* a multiboot entry without LT_HYPER? */
2524     continue;
2525        }
2526        firstElement = 2;
2527    
2528   line = entry->lines;   } else {
2529   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2530   if (!line) continue;      if (!line) {
2531   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2532     continue;
2533          if (entry->multiboot && !multibootArgs) {      }
2534              /* 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;  
2535   }   }
2536    
2537   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2538      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2539      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2540     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2541        /* this is a multiboot entry, make sure there's
2542         * -- on the args line
2543         */
2544        for (i = firstElement; i < line->numElements; i++) {
2545     if (!strcmp(line->elements[i].item, "--"))
2546        break;
2547        }
2548        if (i == line->numElements) {
2549     /* assume all existing args are kernel args,
2550     * prepend -- to make it official
2551     */
2552     insertElement(line, "--", firstElement, cfg->cfi);
2553     i = firstElement;
2554        }
2555        if (!multibootArgs) {
2556     /* kernel args start after the -- */
2557     firstElement = i + 1;
2558        }
2559     } else if (cfg->cfi->mbConcatArgs) {
2560        /* this is a non-multiboot entry, remove hyper args */
2561        for (i = firstElement; i < line->numElements; i++) {
2562     if (!strcmp(line->elements[i].item, "--"))
2563        break;
2564        }
2565        if (i < line->numElements) {
2566     /* remove args up to -- */
2567     while (strcmp(line->elements[firstElement].item, "--"))
2568        removeElement(line, firstElement);
2569     /* remove -- */
2570     removeElement(line, firstElement);
2571        }
2572   }   }
2573    
2574          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2575    
2576          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2577   for (arg = newArgs; *arg; arg++) {  
2578              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2579      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2580     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2581        !strcmp(line->elements[i].item, "--"))
2582     {
2583        /* reached the end of hyper args, insert here */
2584        doreplace = 0;
2585        break;  
2586     }
2587                  if (usedElements[i])                  if (usedElements[i])
2588                      continue;                      continue;
2589   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2590                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2591      break;      break;
2592                  }                  }
2593              }              }
     chptr = strchr(*arg, '=');  
2594    
2595      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2596   /* replace */   /* direct replacement */
2597   free(line->elements[i].item);   free(line->elements[i].item);
2598   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("");  
  }  
2599    
2600   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2601   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2602      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2603   /* append */   if (rootLine) {
2604   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2605   (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(" ");  
2606   } else {   } else {
2607      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2608         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2609   }   }
2610        }
2611    
2612   line->numElements++;      else {
2613     /* insert/append */
2614     insertElement(line, *arg, i, cfg->cfi);
2615     usedElements = realloc(usedElements, line->numElements *
2616           sizeof(*usedElements));
2617     memmove(&usedElements[i + 1], &usedElements[i],
2618     line->numElements - i - 1);
2619     usedElements[i] = 1;
2620    
2621   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2622     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2623     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2624   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2625      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2626      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2627   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2628   }   }
2629      }      }
             k++;  
2630   }   }
2631    
2632          free(usedElements);          free(usedElements);
2633    
  /* 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? */  
2634   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2635      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2636   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2637        !strcmp(line->elements[i].item, "--"))
2638        /* reached the end of hyper args, stop here */
2639        break;
2640     if (!argMatch(line->elements[i].item, *arg)) {
2641        removeElement(line, i);
2642      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;  
2643   }   }
2644        }
2645   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2646        if (useRoot && !strncmp(*arg, "root=", 5)) {
2647   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2648      line->elements[j - 1] = line->elements[j];   if (rootLine)
2649        removeLine(entry, rootLine);
  line->numElements--;  
2650      }      }
2651   }   }
2652    
# Line 1760  int updateActualImage(struct grubConfig Line 2657  int updateActualImage(struct grubConfig
2657   }   }
2658      }      }
2659    
     free(usedArgs);  
2660      free(newArgs);      free(newArgs);
2661      free(oldArgs);      free(oldArgs);
2662    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2682  int updateImage(struct grubConfig * cfg,
2682      return rc;      return rc;
2683  }  }
2684    
2685    int updateInitrd(struct grubConfig * cfg, const char * image,
2686                     const char * prefix, const char * initrd) {
2687        struct singleEntry * entry;
2688        struct singleLine * line, * kernelLine, *endLine = NULL;
2689        int index = 0;
2690    
2691        if (!image) return 0;
2692    
2693        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2694            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2695            if (!kernelLine) continue;
2696    
2697            line = getLineByType(LT_INITRD, entry->lines);
2698            if (line)
2699                removeLine(entry, line);
2700            if (prefix) {
2701                int prefixLen = strlen(prefix);
2702                if (!strncmp(initrd, prefix, prefixLen))
2703                    initrd += prefixLen;
2704            }
2705     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2706     if (endLine)
2707        removeLine(entry, endLine);
2708            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2709            if (!line)
2710        return 1;
2711     if (endLine) {
2712        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2713                if (!line)
2714     return 1;
2715     }
2716    
2717            break;
2718        }
2719    
2720        return 0;
2721    }
2722    
2723  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2724      int fd;      int fd;
2725      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2743  int checkDeviceBootloader(const char * d
2743      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2744   return 0;   return 0;
2745    
2746      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2747   offset = boot[2] + 2;   offset = boot[2] + 2;
2748      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2749   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2750      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2751   offset = boot[1] + 2;        offset = boot[1] + 2;
2752            /*
2753     * it looks like grub, when copying stage1 into the mbr, patches stage1
2754     * right after the JMP location, replacing other instructions such as
2755     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2756     * different bytes.
2757     */
2758          if ((bootSect[offset + 1] == NOOP_OPCODE)
2759      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2760     offset = offset + 3;
2761          }
2762      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2763   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2764      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2900  int checkForLilo(struct grubConfig * con
2900      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2901  }  }
2902    
2903    int checkForGrub2(struct grubConfig * config) {
2904        if (!access("/etc/grub.d/", R_OK))
2905     return 2;
2906    
2907        return 1;
2908    }
2909    
2910  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2911      int fd;      int fd;
2912      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2927  int checkForGrub(struct grubConfig * con
2927      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2928   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2929   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2930     close(fd);
2931     return 1;
2932        }
2933        close(fd);
2934    
2935        return checkDeviceBootloader(boot, bootSect);
2936    }
2937    
2938    int checkForExtLinux(struct grubConfig * config) {
2939        int fd;
2940        unsigned char bootSect[512];
2941        char * boot;
2942        char executable[] = "/boot/extlinux/extlinux";
2943    
2944        printf("entered: checkForExtLinux()\n");
2945    
2946        if (parseSysconfigGrub(NULL, &boot))
2947     return 0;
2948    
2949        /* assume grub is not installed -- not an error condition */
2950        if (!boot)
2951     return 0;
2952    
2953        fd = open(executable, O_RDONLY);
2954        if (fd < 0)
2955     /* this doesn't exist if grub hasn't been installed */
2956     return 0;
2957    
2958        if (read(fd, bootSect, 512) != 512) {
2959     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2960     executable, strerror(errno));
2961   return 1;   return 1;
2962      }      }
2963      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2976  static char * getRootSpecifier(char * st
2976      return rootspec;      return rootspec;
2977  }  }
2978    
2979    static char * getInitrdVal(struct grubConfig * config,
2980       const char * prefix, struct singleLine *tmplLine,
2981       const char * newKernelInitrd,
2982       const char ** extraInitrds, int extraInitrdCount)
2983    {
2984        char *initrdVal, *end;
2985        int i;
2986        size_t totalSize;
2987        size_t prefixLen;
2988        char separatorChar;
2989    
2990        prefixLen = strlen(prefix);
2991        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2992    
2993        for (i = 0; i < extraInitrdCount; i++) {
2994     totalSize += sizeof(separatorChar);
2995     totalSize += strlen(extraInitrds[i]) - prefixLen;
2996        }
2997    
2998        initrdVal = end = malloc(totalSize);
2999    
3000        end = stpcpy (end, newKernelInitrd + prefixLen);
3001    
3002        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3003        for (i = 0; i < extraInitrdCount; i++) {
3004     const char *extraInitrd;
3005     int j;
3006    
3007     extraInitrd = extraInitrds[i] + prefixLen;
3008     /* Don't add entries that are already there */
3009     if (tmplLine != NULL) {
3010        for (j = 2; j < tmplLine->numElements; j++)
3011     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3012        break;
3013    
3014        if (j != tmplLine->numElements)
3015     continue;
3016     }
3017    
3018     *end++ = separatorChar;
3019     end = stpcpy(end, extraInitrd);
3020        }
3021    
3022        return initrdVal;
3023    }
3024    
3025  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3026           const char * prefix,           const char * prefix,
3027   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3028   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3029                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3030                     const char * newMBKernel, const char * newMBKernelArgs) {
3031      struct singleEntry * new;      struct singleEntry * new;
3032      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3033      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3034      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3035    
3036      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3037    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3061  int addNewKernel(struct grubConfig * con
3061      config->entries = new;      config->entries = new;
3062    
3063      /* copy/update from the template */      /* copy/update from the template */
3064      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3065        if (newKernelInitrd)
3066     needs |= NEED_INITRD;
3067      if (newMBKernel) {      if (newMBKernel) {
3068          needs |= KERNEL_MB;          needs |= NEED_MB;
3069          new->multiboot = 1;          new->multiboot = 1;
3070      }      }
3071    
3072      if (template) {      if (template) {
3073   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3074      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3075      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3076   indent = tmplLine->indent;   {
3077        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3078    
3079      /* skip comments */      /* skip comments */
3080      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3081      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3082      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3083    
3084      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3085      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3086     if (!template->multiboot && (needs & NEED_MB)) {
3087              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3088                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3089                  struct singleLine *l;       * hypervisor at the same time.
3090                  needs &= ~ KERNEL_MB;       */
3091        if (config->cfi->mbHyperFirst) {
3092                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3093                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3094                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3095                      newMBKernel + strlen(prefix));
3096                  tmplLine = lastLine;   /* set up for adding the kernel line */
3097                  if (!new->lines) {   free(tmplLine->indent);
3098                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3099                  } else {   needs &= ~NEED_MB;
3100                      newLine->next = l;      }
3101                      newLine = l;      if (needs & NEED_KERNEL) {
3102                  }   /* use addLineTmpl to preserve line elements,
3103                  continue;   * otherwise we could just call addLine.  Unfortunately
3104              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3105                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3106                  continue; /* don't need multiboot kernel here */   * change below.
3107              }   */
3108     struct keywordTypes * mbm_kw =
3109        getKeywordByType(LT_MBMODULE, config->cfi);
3110     if (mbm_kw) {
3111        tmplLine->type = LT_MBMODULE;
3112        free(tmplLine->elements[0].item);
3113        tmplLine->elements[0].item = strdup(mbm_kw->key);
3114     }
3115     newLine = addLineTmpl(new, tmplLine, newLine,
3116          newKernelPath + strlen(prefix), config->cfi);
3117     needs &= ~NEED_KERNEL;
3118        }
3119        if (needs & NEED_MB) { /* !mbHyperFirst */
3120     newLine = addLine(new, config->cfi, LT_HYPER,
3121      config->secondaryIndent,
3122      newMBKernel + strlen(prefix));
3123     needs &= ~NEED_MB;
3124        }
3125     } else if (needs & NEED_KERNEL) {
3126        newLine = addLineTmpl(new, tmplLine, newLine,
3127      newKernelPath + strlen(prefix), config->cfi);
3128        needs &= ~NEED_KERNEL;
3129     }
3130    
3131      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3132   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3133   new->lines = newLine;   if (needs & NEED_MB) {
3134      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3135   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3136   newLine = newLine->next;      needs &= ~NEED_MB;
3137      }   }
3138    
3139        } else if (tmplLine->type == LT_MBMODULE &&
3140           tmplLine->numElements >= 2) {
3141     if (new->multiboot) {
3142        if (needs & NEED_KERNEL) {
3143     newLine = addLineTmpl(new, tmplLine, newLine,
3144          newKernelPath +
3145          strlen(prefix), config->cfi);
3146     needs &= ~NEED_KERNEL;
3147        } else if (config->cfi->mbInitRdIsModule &&
3148           (needs & NEED_INITRD)) {
3149     char *initrdVal;
3150     initrdVal = getInitrdVal(config, prefix, tmplLine,
3151     newKernelInitrd, extraInitrds,
3152     extraInitrdCount);
3153     newLine = addLineTmpl(new, tmplLine, newLine,
3154          initrdVal, config->cfi);
3155     free(initrdVal);
3156     needs &= ~NEED_INITRD;
3157        }
3158     } else if (needs & NEED_KERNEL) {
3159        /* template is multi but new is not,
3160         * insert the kernel in the first module slot
3161         */
3162        tmplLine->type = LT_KERNEL;
3163        free(tmplLine->elements[0].item);
3164        tmplLine->elements[0].item =
3165     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3166        newLine = addLineTmpl(new, tmplLine, newLine,
3167      newKernelPath + strlen(prefix), config->cfi);
3168        needs &= ~NEED_KERNEL;
3169     } else if (needs & NEED_INITRD) {
3170        char *initrdVal;
3171        /* template is multi but new is not,
3172         * insert the initrd in the second module slot
3173         */
3174        tmplLine->type = LT_INITRD;
3175        free(tmplLine->elements[0].item);
3176        tmplLine->elements[0].item =
3177     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3178        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3179        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3180        free(initrdVal);
3181        needs &= ~NEED_INITRD;
3182     }
3183    
     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));  
                 }  
3184      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3185      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3186   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3187   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3188                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3189                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3190                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3191                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3192                  }       */
3193                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3194                  if (rootspec != NULL) {   char *initrdVal;
3195                      newLine->elements[1].item = sdupprintf("%s%s",  
3196                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3197                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3198                                                             strlen(prefix));    config->secondaryIndent,
3199                  } else {    initrdVal);
3200                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3201                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3202                  }      }
3203              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3204                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3205   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3206                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3207                      free(newLine->elements[0].item);      free(initrdVal);
3208                      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);  
3209   }   }
3210    
3211   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3212   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3213   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3214     char *nkt = malloc(strlen(newKernelTitle)+3);
3215     strcpy(nkt, "'");
3216     strcat(nkt, newKernelTitle);
3217     strcat(nkt, "'");
3218     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3219     free(nkt);
3220     needs &= ~NEED_TITLE;
3221      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3222                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3223                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3224                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3225                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3226                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3227                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3228                                             newLine->numElements);     config->cfi->titleBracketed) {
3229        /* addLineTmpl doesn't handle titleBracketed */
3230                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3231                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3232                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3233                  newLine->numElements = 1;   }
3234              }      } else if (tmplLine->type == LT_ECHO) {
3235        requote(tmplLine, config->cfi);
3236        static const char *prefix = "'Loading ";
3237        if (tmplLine->numElements > 1 &&
3238        strstr(tmplLine->elements[1].item, prefix) &&
3239        masterLine->next && masterLine->next->type == LT_KERNEL) {
3240     char *newTitle = malloc(strlen(prefix) +
3241     strlen(newKernelTitle) + 2);
3242    
3243     strcpy(newTitle, prefix);
3244     strcat(newTitle, newKernelTitle);
3245     strcat(newTitle, "'");
3246     newLine = addLine(new, config->cfi, LT_ECHO,
3247     tmplLine->indent, newTitle);
3248     free(newTitle);
3249        } else {
3250     /* pass through other lines from the template */
3251     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3252     config->cfi);
3253        }
3254        } else {
3255     /* pass through other lines from the template */
3256     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3257        }
3258   }   }
3259    
3260      } else {      } else {
3261   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3262      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3263     */
3264     switch (config->cfi->entryStart) {
3265        case LT_KERNEL:
3266     if (new->multiboot && config->cfi->mbHyperFirst) {
3267        /* fall through to LT_HYPER */
3268     } else {
3269        newLine = addLine(new, config->cfi, LT_KERNEL,
3270          config->primaryIndent,
3271          newKernelPath + strlen(prefix));
3272        needs &= ~NEED_KERNEL;
3273        break;
3274     }
3275    
3276        case LT_HYPER:
3277     newLine = addLine(new, config->cfi, LT_HYPER,
3278      config->primaryIndent,
3279      newMBKernel + strlen(prefix));
3280     needs &= ~NEED_MB;
3281   break;   break;
         }  
3282    
3283   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3284      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3285       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3286       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3287      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3288       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3289      default:        config->primaryIndent, nkt);
3290                  /* zipl strikes again */   free(nkt);
3291                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3292                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3293                      chptr = newKernelTitle;   break;
3294                      type = LT_TITLE;      }
3295                      break;      case LT_TITLE:
3296                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3297                      abort();   char * templabel;
3298                  }   int x = 0, y = 0;
3299   }  
3300     templabel = strdup(newKernelTitle);
3301     while( templabel[x]){
3302     if( templabel[x] == ' ' ){
3303     y = x;
3304     while( templabel[y] ){
3305     templabel[y] = templabel[y+1];
3306     y++;
3307     }
3308     }
3309     x++;
3310     }
3311     newLine = addLine(new, config->cfi, LT_TITLE,
3312      config->primaryIndent, templabel);
3313     free(templabel);
3314     }else{
3315     newLine = addLine(new, config->cfi, LT_TITLE,
3316      config->primaryIndent, newKernelTitle);
3317     }
3318     needs &= ~NEED_TITLE;
3319     break;
3320    
3321   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3322   new->lines = newLine;   abort();
3323     }
3324      }      }
3325    
3326      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3327          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3328              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3329                                config->secondaryIndent,       */
3330                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3331          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3332              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3333                                config->secondaryIndent,    newKernelTitle);
3334                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3335          /* don't need to check for title as it's guaranteed to have been      }
3336           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3337           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3338          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3339              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3340                                config->secondaryIndent,   needs &= ~NEED_MB;
3341                                newKernelInitrd + strlen(prefix));      }
3342      } else {      if (needs & NEED_KERNEL) {
3343          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3344              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3345                                config->secondaryIndent,        config->cfi)) ?
3346                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3347          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3348              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3349                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3350                                newKernelTitle);      }
3351          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3352              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3353                                config->secondaryIndent,    config->secondaryIndent,
3354                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3355     needs &= ~NEED_MB;
3356        }
3357        if (needs & NEED_INITRD) {
3358     char *initrdVal;
3359     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3360     newLine = addLine(new, config->cfi,
3361      (new->multiboot && getKeywordByType(LT_MBMODULE,
3362          config->cfi)) ?
3363      LT_MBMODULE : LT_INITRD,
3364      config->secondaryIndent,
3365      initrdVal);
3366     free(initrdVal);
3367     needs &= ~NEED_INITRD;
3368        }
3369        if (needs & NEED_END) {
3370     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3371     config->secondaryIndent, NULL);
3372     needs &= ~NEED_END;
3373        }
3374    
3375        if (needs) {
3376     printf(_("grubby: needs=%d, aborting\n"), needs);
3377     abort();
3378      }      }
3379    
3380      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3383  int addNewKernel(struct grubConfig * con
3383      return 0;      return 0;
3384  }  }
3385    
3386    static void traceback(int signum)
3387    {
3388        void *array[40];
3389        size_t size;
3390    
3391        signal(SIGSEGV, SIG_DFL);
3392        memset(array, '\0', sizeof (array));
3393        size = backtrace(array, 40);
3394    
3395        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3396                (unsigned long)size);
3397        backtrace_symbols_fd(array, size, STDERR_FILENO);
3398        exit(1);
3399    }
3400    
3401  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3402      poptContext optCon;      poptContext optCon;
3403      char * grubConfig = NULL;      const char * grubConfig = NULL;
3404      char * outputFile = NULL;      char * outputFile = NULL;
3405      int arg = 0;      int arg = 0;
3406      int flags = 0;      int flags = 0;
3407      int badImageOkay = 0;      int badImageOkay = 0;
3408        int configureGrub2 = 0;
3409      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3410      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3411        int configureExtLinux = 0;
3412      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3413        int extraInitrdCount = 0;
3414      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3415      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3416      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3426  int main(int argc, const char ** argv) {
3426      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3427      char * removeArgs = NULL;      char * removeArgs = NULL;
3428      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3429        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3430      const char * chptr = NULL;      const char * chptr = NULL;
3431      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3432      struct grubConfig * config;      struct grubConfig * config;
3433      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3434      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3435      int displayDefault = 0;      int displayDefault = 0;
3436        int displayDefaultIndex = 0;
3437        int displayDefaultTitle = 0;
3438      struct poptOption options[] = {      struct poptOption options[] = {
3439   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3440      _("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 3465  int main(int argc, const char ** argv) {
3465        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3466        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3467        "template"), NULL },        "template"), NULL },
3468     { "debug", 0, 0, &debug, 0,
3469        _("print debugging information for failures") },
3470   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3471      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3472     { "default-index", 0, 0, &displayDefaultIndex, 0,
3473        _("display the index of the default kernel") },
3474     { "default-title", 0, 0, &displayDefaultTitle, 0,
3475        _("display the title of the default kernel") },
3476   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3477      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3478     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3479        _("configure extlinux bootloader (from syslinux)") },
3480   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3481      _("configure grub bootloader") },      _("configure grub bootloader") },
3482     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3483        _("configure grub2 bootloader") },
3484   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3485      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3486      _("kernel-path") },      _("kernel-path") },
3487   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3488      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3489     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3490        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3491   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3492      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3493   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3524  int main(int argc, const char ** argv) {
3524   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3525      };      };
3526    
3527        useextlinuxmenu=0;
3528    
3529        signal(SIGSEGV, traceback);
3530    
3531      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3532      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3533    
# Line 2391  int main(int argc, const char ** argv) { Line 3537  int main(int argc, const char ** argv) {
3537      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3538      exit(0);      exit(0);
3539      break;      break;
3540      case 'i':
3541        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3542         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3543        } else {
3544     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3545     return 1;
3546        }
3547        break;
3548   }   }
3549      }      }
3550    
# Line 2406  int main(int argc, const char ** argv) { Line 3560  int main(int argc, const char ** argv) {
3560   return 1;   return 1;
3561      }      }
3562    
3563      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3564   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3565     configureExtLinux ) > 1) {
3566   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3567   return 1;   return 1;
3568      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3569   fprintf(stderr,   fprintf(stderr,
3570      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3571   return 1;   return 1;
3572        } else if (configureGrub2) {
3573     cfi = &grub2ConfigType;
3574      } else if (configureLilo) {      } else if (configureLilo) {
3575   cfi = &liloConfigType;   cfi = &liloConfigType;
3576      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3583  int main(int argc, const char ** argv) {
3583          cfi = &siloConfigType;          cfi = &siloConfigType;
3584      } else if (configureZipl) {      } else if (configureZipl) {
3585          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3586        } else if (configureExtLinux) {
3587     cfi = &extlinuxConfigType;
3588     useextlinuxmenu=1;
3589      }      }
3590    
3591      if (!cfi) {      if (!cfi) {
3592            if (grub2FindConfig(&grub2ConfigType))
3593        cfi = &grub2ConfigType;
3594     else
3595        #ifdef __ia64__        #ifdef __ia64__
3596   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3597        #elif __powerpc__        #elif __powerpc__
3598   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3599        #elif __sparc__        #elif __sparc__
3600          cfi = &siloConfigType;              cfi = &siloConfigType;
3601        #elif __s390__        #elif __s390__
3602          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3603        #elif __s390x__        #elif __s390x__
3604          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3605        #else        #else
3606   cfi = &grubConfigType;      cfi = &grubConfigType;
3607        #endif        #endif
3608      }      }
3609    
3610      if (!grubConfig)      if (!grubConfig) {
3611   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3612        grubConfig = cfi->findConfig(cfi);
3613     if (!grubConfig)
3614        grubConfig = cfi->defaultConfig;
3615        }
3616    
3617      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3618    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3619    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3620   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3621    "specified option"));    "specified option"));
3622   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3632  int main(int argc, const char ** argv) {
3632      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3633   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3634   return 1;   return 1;
3635      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3636    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3637    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3638   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3639   return 1;   return 1;
3640      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3659  int main(int argc, const char ** argv) {
3659   defaultKernel = NULL;   defaultKernel = NULL;
3660      }      }
3661    
3662      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3663   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3664   "is used\n"));   "is used\n"));
3665   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3667  int main(int argc, const char ** argv) {
3667    
3668      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3669   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3670          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3671   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3672   return 1;   return 1;
3673      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3687  int main(int argc, const char ** argv) {
3687   bootPrefix = "";   bootPrefix = "";
3688      }      }
3689    
3690        if (!cfi->mbAllowExtraInitRds &&
3691     extraInitrdCount > 0) {
3692     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3693     return 1;
3694        }
3695    
3696      if (bootloaderProbe) {      if (bootloaderProbe) {
3697   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3698   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3699    
3700   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3701      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3702        gconfig = readConfig(grub2config, &grub2ConfigType);
3703        if (!gconfig)
3704     gr2c = 1;
3705        else
3706     gr2c = checkForGrub2(gconfig);
3707     }
3708    
3709     const char *grubconfig = grubFindConfig(&grubConfigType);
3710     if (!access(grubconfig, F_OK)) {
3711        gconfig = readConfig(grubconfig, &grubConfigType);
3712      if (!gconfig)      if (!gconfig)
3713   grc = 1;   grc = 1;
3714      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3723  int main(int argc, const char ** argv) {
3723   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3724   }   }
3725    
3726   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3727        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3728        if (!lconfig)
3729     erc = 1;
3730        else
3731     erc = checkForExtLinux(lconfig);
3732     }
3733    
3734     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3735    
3736   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3737     if (gr2c == 2) printf("grub2\n");
3738   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3739     if (erc == 2) printf("extlinux\n");
3740    
3741   return 0;   return 0;
3742      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3754  int main(int argc, const char ** argv) {
3754   if (!entry) return 0;   if (!entry) return 0;
3755   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3756    
3757   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3758   if (!line) return 0;   if (!line) return 0;
3759    
3760          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3762  int main(int argc, const char ** argv) {
3762                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3763    
3764   return 0;   return 0;
3765    
3766        } else if (displayDefaultTitle) {
3767     struct singleLine * line;
3768     struct singleEntry * entry;
3769    
3770     if (config->defaultImage == -1) return 0;
3771     entry = findEntryByIndex(config, config->defaultImage);
3772     if (!entry) return 0;
3773    
3774     if (!configureGrub2) {
3775      line = getLineByType(LT_TITLE, entry->lines);
3776      if (!line) return 0;
3777      printf("%s\n", line->elements[1].item);
3778    
3779     } else {
3780      char * title;
3781    
3782      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3783      line = getLineByType(LT_MENUENTRY, entry->lines);
3784      if (!line) return 0;
3785      title = grub2ExtractTitle(line);
3786      if (title)
3787        printf("%s\n", title);
3788     }
3789     return 0;
3790    
3791        } else if (displayDefaultIndex) {
3792            if (config->defaultImage == -1) return 0;
3793            printf("%i\n", config->defaultImage);
3794    
3795      } else if (kernelInfo)      } else if (kernelInfo)
3796   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3797    
# Line 2585  int main(int argc, const char ** argv) { Line 3807  int main(int argc, const char ** argv) {
3807      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3808      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3809                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3810        if (updateKernelPath && newKernelInitrd) {
3811                if (updateInitrd(config, updateKernelPath, bootPrefix,
3812                                 newKernelInitrd)) return 1;
3813        }
3814      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3815                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3816                         (const char **)extraInitrds, extraInitrdCount,
3817                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3818            
3819    
# Line 2597  int main(int argc, const char ** argv) { Line 3824  int main(int argc, const char ** argv) {
3824      }      }
3825    
3826      if (!outputFile)      if (!outputFile)
3827   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3828    
3829      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3830  }  }

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