Magellan Linux

Diff of /tags/grubby-8_36/grubby.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1931 by niro, Mon Oct 1 12:06:26 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     "/boot/grub/grub.conf",
168     "/boot/grub/menu.lst",
169     "/etc/grub.conf",
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        { "linuxefi",   LT_KERNEL,      ' ' },
209        { "initrd",     LT_INITRD,      ' ', ' ' },
210        { "initrdefi",  LT_INITRD,      ' ', ' ' },
211        { "module",     LT_MBMODULE,    ' ' },
212        { "kernel",     LT_HYPER,       ' ' },
213        { NULL, 0, 0 },
214    };
215    
216    const char *grub2FindConfig(struct configFileInfo *cfi) {
217        static const char *configFiles[] = {
218     "/boot/grub/grub-efi.cfg",
219     "/boot/grub/grub.cfg",
220     NULL
221        };
222        static int i = -1;
223        static const char *grub_cfg = "/boot/grub/grub.cfg";
224    
225        if (i == -1) {
226     for (i = 0; configFiles[i] != NULL; i++) {
227        dbgPrintf("Checking \"%s\": ", configFiles[i]);
228        if (!access(configFiles[i], R_OK)) {
229     dbgPrintf("found\n");
230     return configFiles[i];
231        }
232     }
233        }
234    
235        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
236         * that isn't in grub1, and if it exists, return the config file path
237         * that they use. */
238        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
239     dbgPrintf("found\n");
240     return grub_cfg;
241        }
242    
243        dbgPrintf("not found\n");
244        return configFiles[i];
245    }
246    
247    int sizeOfSingleLine(struct singleLine * line) {
248      int count = 0;
249    
250      for (int i = 0; i < line->numElements; i++) {
251        int indentSize = 0;
252    
253        count = count + strlen(line->elements[i].item);
254    
255        indentSize = strlen(line->elements[i].indent);
256        if (indentSize > 0)
257          count = count + indentSize;
258        else
259          /* be extra safe and add room for whitespaces */
260          count = count + 1;
261      }
262    
263      /* room for trailing terminator */
264      count = count + 1;
265    
266      return count;
267    }
268    
269    static int isquote(char q)
270    {
271        if (q == '\'' || q == '\"')
272     return 1;
273        return 0;
274    }
275    
276    char *grub2ExtractTitle(struct singleLine * line) {
277        char * current;
278        char * current_indent;
279        int current_len;
280        int current_indent_len;
281        int i;
282    
283        /* bail out if line does not start with menuentry */
284        if (strcmp(line->elements[0].item, "menuentry"))
285          return NULL;
286    
287        i = 1;
288        current = line->elements[i].item;
289        current_len = strlen(current);
290    
291        /* if second word is quoted, strip the quotes and return single word */
292        if (isquote(*current) && isquote(current[current_len - 1])) {
293     char *tmp;
294    
295     tmp = strdup(current);
296     *(tmp + current_len - 1) = '\0';
297     return ++tmp;
298        }
299    
300        /* if no quotes, return second word verbatim */
301        if (!isquote(*current))
302     return current;
303    
304        /* second element start with a quote, so we have to find the element
305         * whose last character is also quote (assuming it's the closing one) */
306        int resultMaxSize;
307        char * result;
308        
309        resultMaxSize = sizeOfSingleLine(line);
310        result = malloc(resultMaxSize);
311        snprintf(result, resultMaxSize, "%s", ++current);
312        
313        i++;
314        for (; i < line->numElements; ++i) {
315     current = line->elements[i].item;
316     current_len = strlen(current);
317     current_indent = line->elements[i].indent;
318     current_indent_len = strlen(current_indent);
319    
320     strncat(result, current_indent, current_indent_len);
321     if (!isquote(current[current_len-1])) {
322        strncat(result, current, current_len);
323     } else {
324        strncat(result, current, current_len - 1);
325        break;
326     }
327        }
328        return result;
329    }
330    
331    struct configFileInfo grub2ConfigType = {
332        .findConfig = grub2FindConfig,
333        .keywords = grub2Keywords,
334        .defaultIsIndex = 1,
335        .defaultSupportSaved = 1,
336        .defaultIsVariable = 1,
337        .entryStart = LT_MENUENTRY,
338        .entryEnd = LT_ENTRY_END,
339        .titlePosition = 1,
340        .needsBootPrefix = 1,
341        .mbHyperFirst = 1,
342        .mbInitRdIsModule = 1,
343        .mbAllowExtraInitRds = 1,
344  };  };
345    
346  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 374  struct keywordTypes yabootKeywords[] = {
374      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
375      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
376      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
377      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
378      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
379      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
380      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 394  struct keywordTypes liloKeywords[] = {
394      { NULL,    0, 0 },      { NULL,    0, 0 },
395  };  };
396    
397    struct keywordTypes eliloKeywords[] = {
398        { "label",    LT_TITLE,    '=' },
399        { "root",    LT_ROOT,    '=' },
400        { "default",    LT_DEFAULT,    '=' },
401        { "image",    LT_KERNEL,    '=' },
402        { "initrd",    LT_INITRD,    '=' },
403        { "append",    LT_KERNELARGS,  '=' },
404        { "vmm",    LT_HYPER,       '=' },
405        { NULL,    0, 0 },
406    };
407    
408  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
409      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
410      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 426  struct keywordTypes ziplKeywords[] = {
426      { NULL,         0, 0 },      { NULL,         0, 0 },
427  };  };
428    
429    struct keywordTypes extlinuxKeywords[] = {
430        { "label",    LT_TITLE,    ' ' },
431        { "root",    LT_ROOT,    ' ' },
432        { "default",    LT_DEFAULT,    ' ' },
433        { "kernel",    LT_KERNEL,    ' ' },
434        { "initrd",    LT_INITRD,      ' ', ',' },
435        { "append",    LT_KERNELARGS,  ' ' },
436        { "prompt",     LT_UNKNOWN,     ' ' },
437        { NULL,    0, 0 },
438    };
439    int useextlinuxmenu;
440  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
441      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
442      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
443      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
444      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
445      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
446      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
447  };  };
448    
449  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
450      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
451      liloKeywords,    /* keywords */      .keywords = liloKeywords,
452      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
453      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
454      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
455  };  };
456    
457  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
458      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
459      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
460      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
461      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
462      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
463      1,    /* needsBootPrefix */      .maxTitleLength = 15,
464      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
465  };  };
466    
467  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
468      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
469      siloKeywords,    /* keywords */      .keywords = siloKeywords,
470      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
471      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
472      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
473      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
474  };  };
475    
476  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
477      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
478      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
479      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
480      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
481      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
482      0,    /* needsBootPrefix */  };
483      1,    /* argsInQuotes */  
484      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
485      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
486        .keywords = extlinuxKeywords,
487        .entryStart = LT_TITLE,
488        .needsBootPrefix = 1,
489        .maxTitleLength = 255,
490        .mbAllowExtraInitRds = 1,
491  };  };
492    
493  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 502  struct grubConfig {
502      struct configFileInfo * cfi;      struct configFileInfo * cfi;
503  };  };
504    
505    blkid_cache blkid;
506    
507  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
508  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
509       const char * path, const char * prefix,       const char * path, const char * prefix,
510       int * index);       int * index);
 static char * strndup(char * from, int len);  
511  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
512  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
513    struct singleLine * lineDup(struct singleLine * line);
514  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
515  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
516       struct configFileInfo * cfi);       struct configFileInfo * cfi);
517  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
518         struct configFileInfo * cfi);         struct configFileInfo * cfi);
519  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
520    static void requote(struct singleLine *line, struct configFileInfo * cfi);
521  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
522      char * to;    const char * item, int insertHere,
523      struct configFileInfo * cfi);
524      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
525      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
526      to[len] = '\0';        struct configFileInfo * cfi);
527    static enum lineType_e getTypeByKeyword(char * keyword,
528      return to;   struct configFileInfo * cfi);
529  }  static struct singleLine * getLineByType(enum lineType_e type,
530     struct singleLine * line);
531    static int checkForExtLinux(struct grubConfig * config);
532    struct singleLine * addLineTmpl(struct singleEntry * entry,
533                                    struct singleLine * tmplLine,
534                                    struct singleLine * prevLine,
535                                    const char * val,
536     struct configFileInfo * cfi);
537    struct singleLine *  addLine(struct singleEntry * entry,
538                                 struct configFileInfo * cfi,
539                                 enum lineType_e type, char * defaultIndent,
540                                 const char * val);
541    
542  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
543  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 572  static char * sdupprintf(const char *for
572      return buf;      return buf;
573  }  }
574    
575    static struct keywordTypes * getKeywordByType(enum lineType_e type,
576          struct configFileInfo * cfi) {
577        for (struct keywordTypes *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        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
608     if (!strcmp(keyword, kw->key))
609        return kw->type;
610        }
611        return LT_UNKNOWN;
612    }
613    
614    static struct singleLine * getLineByType(enum lineType_e type,
615     struct singleLine * line) {
616        dbgPrintf("getLineByType(%d): ", type);
617        for (; line; line = line->next) {
618     dbgPrintf("%d:%s ", line->type,
619      line->numElements ? line->elements[0].item : "(empty)");
620     if (line->type & type) break;
621        }
622        dbgPrintf(line ? "\n" : " (failed)\n");
623        return line;
624    }
625    
626  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
627      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
628          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
629          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
630              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 636  static int isBracketedTitle(struct singl
636      return 0;      return 0;
637  }  }
638    
639  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
640                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
641      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
642   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;  
643  }  }
644    
645  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 690  static void lineInit(struct singleLine *
690      line->next = NULL;      line->next = NULL;
691  }  }
692    
693  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
694      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
695    
696        newLine->indent = strdup(line->indent);
697        newLine->next = NULL;
698        newLine->type = line->type;
699        newLine->numElements = line->numElements;
700        newLine->elements = malloc(sizeof(*newLine->elements) *
701           newLine->numElements);
702    
703        for (int i = 0; i < newLine->numElements; i++) {
704     newLine->elements[i].indent = strdup(line->elements[i].indent);
705     newLine->elements[i].item = strdup(line->elements[i].item);
706        }
707    
708        return newLine;
709    }
710    
711    static void lineFree(struct singleLine * line) {
712      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
713    
714      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
715   free(line->elements[i].item);   free(line->elements[i].item);
716   free(line->elements[i].indent);   free(line->elements[i].indent);
717      }      }
# Line 405  static void lineFree(struct singleLine * Line 722  static void lineFree(struct singleLine *
722    
723  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
724       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
725      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
726    
727      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
728     /* Need to handle this, because we strip the quotes from
729     * menuentry when read it. */
730     if (line->type == LT_MENUENTRY && i == 1) {
731        if(!isquote(*line->elements[i].item))
732     fprintf(out, "\'%s\'", line->elements[i].item);
733        else
734     fprintf(out, "%s", line->elements[i].item);
735        fprintf(out, "%s", line->elements[i].indent);
736    
737        continue;
738     }
739    
740   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
741      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
742    
743   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
744   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
745        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
746      }      }
747    
748      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 761  static int getNextLine(char ** bufPtr, s
761      char * chptr;      char * chptr;
762      int elementsAlloced = 0;      int elementsAlloced = 0;
763      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
764      int first = 1;      int first = 1;
     int i;  
765    
766      lineFree(line);      lineFree(line);
767    
# Line 489  static int getNextLine(char ** bufPtr, s Line 815  static int getNextLine(char ** bufPtr, s
815      if (!line->numElements)      if (!line->numElements)
816   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
817      else {      else {
818   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
819      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;  
               
820              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
821               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
822              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 830  static int getNextLine(char ** bufPtr, s
830      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
831   char * fullLine;   char * fullLine;
832   int len;   int len;
  int i;  
833    
834   len = strlen(line->indent);   len = strlen(line->indent);
835   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
836      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
837     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
838    
# Line 522  static int getNextLine(char ** bufPtr, s Line 841  static int getNextLine(char ** bufPtr, s
841   free(line->indent);   free(line->indent);
842   line->indent = fullLine;   line->indent = fullLine;
843    
844   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
845      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
846      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
847      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 851  static int getNextLine(char ** bufPtr, s
851   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
852   line->numElements = 0;   line->numElements = 0;
853      }      }
854     } else {
855     struct keywordTypes *kw;
856    
857     kw = getKeywordByType(line->type, cfi);
858    
859     /* space isn't the only separator, we need to split
860     * elements up more
861     */
862     if (!isspace(kw->separatorChar)) {
863        char indent[2] = "";
864        indent[0] = kw->separatorChar;
865        for (int i = 1; i < line->numElements; i++) {
866     char *p;
867     int numNewElements;
868    
869     numNewElements = 0;
870     p = line->elements[i].item;
871     while (*p != '\0') {
872     if (*p == kw->separatorChar)
873     numNewElements++;
874     p++;
875     }
876     if (line->numElements + numNewElements >= elementsAlloced) {
877     elementsAlloced += numNewElements + 5;
878     line->elements = realloc(line->elements,
879        sizeof(*line->elements) * elementsAlloced);
880     }
881    
882     for (int j = line->numElements; j > i; j--) {
883     line->elements[j + numNewElements] = line->elements[j];
884     }
885     line->numElements += numNewElements;
886    
887     p = line->elements[i].item;
888     while (*p != '\0') {
889    
890     while (*p != kw->separatorChar && *p != '\0') p++;
891     if (*p == '\0') {
892     break;
893     }
894    
895     line->elements[i + 1].indent = line->elements[i].indent;
896     line->elements[i].indent = strdup(indent);
897     *p++ = '\0';
898     i++;
899     line->elements[i].item = strdup(p);
900     }
901        }
902     }
903   }   }
904      }      }
905    
# Line 549  static struct grubConfig * readConfig(co Line 917  static struct grubConfig * readConfig(co
917      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
918      char * end;      char * end;
919      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
920      int i, len;      int len;
921      char * buf;      char * buf;
922    
923      if (!strcmp(inName, "-")) {      if (!strcmp(inName, "-")) {
# Line 595  static struct grubConfig * readConfig(co Line 963  static struct grubConfig * readConfig(co
963      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
964   }   }
965    
966   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
967      sawEntry = 1;      sawEntry = 1;
968      if (!entry) {      if (!entry) {
969   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 979  static struct grubConfig * readConfig(co
979      entry->next = NULL;      entry->next = NULL;
980   }   }
981    
982   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
983        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
984        dbgPrintf("%s", line->indent);
985        for (int i = 0; i < line->numElements; i++)
986     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
987        dbgPrintf("\n");
988        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
989        if (kwType && line->numElements == 3 &&
990        !strcmp(line->elements[1].item, kwType->key)) {
991     dbgPrintf("Line sets default config\n");
992     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
993     defaultLine = line;
994        }
995     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
996      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
997      defaultLine = line;      defaultLine = line;
998    
999            } else if (line->type == LT_KERNEL) {
1000        /* if by some freak chance this is multiboot and the "module"
1001         * lines came earlier in the template, make sure to use LT_HYPER
1002         * instead of LT_KERNEL now
1003         */
1004        if (entry->multiboot)
1005     line->type = LT_HYPER;
1006    
1007          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1008        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1009         * instead, now that we know this is a multiboot entry.
1010         * This only applies to grub, but that's the only place we
1011         * should find LT_MBMODULE lines anyway.
1012         */
1013        for (struct singleLine *l = entry->lines; l; l = l->next) {
1014     if (l->type == LT_HYPER)
1015        break;
1016     else if (l->type == LT_KERNEL) {
1017        l->type = LT_HYPER;
1018        break;
1019     }
1020        }
1021              entry->multiboot = 1;              entry->multiboot = 1;
1022    
1023     } else if (line->type == LT_HYPER) {
1024        entry->multiboot = 1;
1025    
1026   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1027      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1028      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1029    
1030   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1031      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1032      len = 0;      len = 0;
1033      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1034   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1035   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1036      }      }
1037      buf = malloc(len + 1);      buf = malloc(len + 1);
1038      *buf = '\0';      *buf = '\0';
1039    
1040      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1041   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1042   free(line->elements[i].item);   free(line->elements[i].item);
1043    
# Line 643  static struct grubConfig * readConfig(co Line 1051  static struct grubConfig * readConfig(co
1051      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1052      line->elements[1].item = buf;      line->elements[1].item = buf;
1053      line->numElements = 2;      line->numElements = 2;
1054     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1055        /* let --remove-kernel="TITLE=what" work */
1056        len = 0;
1057        char *extras;
1058        char *title;
1059    
1060        for (int i = 1; i < line->numElements; i++) {
1061     len += strlen(line->elements[i].item);
1062     len += strlen(line->elements[i].indent);
1063        }
1064        buf = malloc(len + 1);
1065        *buf = '\0';
1066    
1067        /* allocate mem for extra flags. */
1068        extras = malloc(len + 1);
1069        *extras = '\0';
1070    
1071        /* get title. */
1072        for (int i = 0; i < line->numElements; i++) {
1073     if (!strcmp(line->elements[i].item, "menuentry"))
1074        continue;
1075     if (isquote(*line->elements[i].item))
1076        title = line->elements[i].item + 1;
1077     else
1078        title = line->elements[i].item;
1079    
1080     len = strlen(title);
1081            if (isquote(title[len-1])) {
1082        strncat(buf, title,len-1);
1083        break;
1084     } else {
1085        strcat(buf, title);
1086        strcat(buf, line->elements[i].indent);
1087     }
1088        }
1089    
1090        /* get extras */
1091        int count = 0;
1092        for (int i = 0; i < line->numElements; i++) {
1093     if (count >= 2) {
1094        strcat(extras, line->elements[i].item);
1095        strcat(extras, line->elements[i].indent);
1096     }
1097    
1098     if (!strcmp(line->elements[i].item, "menuentry"))
1099        continue;
1100    
1101     /* count ' or ", there should be two in menuentry line. */
1102     if (isquote(*line->elements[i].item))
1103        count++;
1104    
1105     len = strlen(line->elements[i].item);
1106    
1107     if (isquote(line->elements[i].item[len -1]))
1108        count++;
1109    
1110     /* ok, we get the final ' or ", others are extras. */
1111                }
1112        line->elements[1].indent =
1113     line->elements[line->numElements - 2].indent;
1114        line->elements[1].item = buf;
1115        line->elements[2].indent =
1116     line->elements[line->numElements - 2].indent;
1117        line->elements[2].item = extras;
1118        line->numElements = 3;
1119   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1120      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1121         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 1124  static struct grubConfig * readConfig(co
1124      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1125   int last, len;   int last, len;
1126    
1127   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1128      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1129     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1130    
1131   last = line->numElements - 1;   last = line->numElements - 1;
1132   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1133   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1134      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1135      }      }
   
1136   }   }
1137    
1138   /* 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 1152  static struct grubConfig * readConfig(co
1152   movedLine = 1;   movedLine = 1;
1153   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1154   }   }
1155    
1156   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1157     which was moved, drop it. */     which was moved, drop it. */
1158   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 1168  static struct grubConfig * readConfig(co
1168   entry->lines = line;   entry->lines = line;
1169      else      else
1170   last->next = line;   last->next = line;
1171        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1172    
1173        /* we could have seen this outside of an entry... if so, we
1174         * ignore it like any other line we don't grok */
1175        if (line->type == LT_ENTRY_END && sawEntry)
1176     sawEntry = 0;
1177   } else {   } else {
1178      if (!cfg->theLines)      if (!cfg->theLines)
1179   cfg->theLines = line;   cfg->theLines = line;
1180      else {      else
1181   last->next = line;   last->next = line;
1182      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1183   }   }
1184    
1185   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1187  static struct grubConfig * readConfig(co
1187    
1188      free(incoming);      free(incoming);
1189    
1190        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1191      if (defaultLine) {      if (defaultLine) {
1192   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1193        cfi->defaultSupportSaved &&
1194        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1195        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1196     } else if (cfi->defaultIsVariable) {
1197        char *value = defaultLine->elements[2].item;
1198        while (*value && (*value == '"' || *value == '\'' ||
1199        *value == ' ' || *value == '\t'))
1200     value++;
1201        cfg->defaultImage = strtol(value, &end, 10);
1202        while (*end && (*end == '"' || *end == '\'' ||
1203        *end == ' ' || *end == '\t'))
1204     end++;
1205        if (*end) cfg->defaultImage = -1;
1206     } else if (cfi->defaultSupportSaved &&
1207   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1208      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1209   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1210      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1211      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1212   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1213      i = 0;      int i = 0;
1214      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1215   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1216      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1224  static struct grubConfig * readConfig(co
1224                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1225                  }                  }
1226   i++;   i++;
1227     entry = NULL;
1228      }      }
1229    
1230      if (entry) cfg->defaultImage = i;      if (entry){
1231            cfg->defaultImage = i;
1232        }else{
1233            cfg->defaultImage = -1;
1234        }
1235   }   }
1236        } else {
1237            cfg->defaultImage = 0;
1238      }      }
1239    
1240      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1250  static void writeDefault(FILE * out, cha
1250    
1251      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1252   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1253        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1254     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1255      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1256   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1257      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1258      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1259     cfg->defaultImage);
1260        } else {
1261     fprintf(out, "%sdefault%s%d\n", indent, separator,
1262     cfg->defaultImage);
1263        }
1264   } else {   } else {
1265      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1266    
# Line 769  static void writeDefault(FILE * out, cha Line 1277  static void writeDefault(FILE * out, cha
1277    
1278      if (!entry) return;      if (!entry) return;
1279    
1280      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1281    
1282      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1283   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1311  static int writeConfig(struct grubConfig
1311      int rc;      int rc;
1312    
1313      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1314         directory to / */         directory to the dir of the symlink */
1315      rc = chdir("/");      char *dir = strdupa(outName);
1316                rc = chdir(dirname(dir));
1317        free(dir);
1318      do {      do {
1319   buf = alloca(len + 1);   buf = alloca(len + 1);
1320   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1321   if (rc == len) len += 256;   if (rc == len) len += 256;
1322      } while (rc == len);      } while (rc == len);
1323            
# Line 843  static int writeConfig(struct grubConfig Line 1352  static int writeConfig(struct grubConfig
1352      }      }
1353    
1354      line = cfg->theLines;      line = cfg->theLines;
1355        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1356      while (line) {      while (line) {
1357   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1358     line->numElements == 3 &&
1359     !strcmp(line->elements[1].item, defaultKw->key)) {
1360        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1361        needs &= ~MAIN_DEFAULT;
1362     } else if (line->type == LT_DEFAULT) {
1363      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1364      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1365   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1427  static int numEntries(struct grubConfig
1427      return i;      return i;
1428  }  }
1429    
1430    static char *findDiskForRoot()
1431    {
1432        int fd;
1433        char buf[65536];
1434        char *devname;
1435        char *chptr;
1436        int rc;
1437    
1438        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1439            fprintf(stderr, "grubby: failed to open %s: %s\n",
1440                    _PATH_MOUNTED, strerror(errno));
1441            return NULL;
1442        }
1443    
1444        rc = read(fd, buf, sizeof(buf) - 1);
1445        if (rc <= 0) {
1446            fprintf(stderr, "grubby: failed to read %s: %s\n",
1447                    _PATH_MOUNTED, strerror(errno));
1448            close(fd);
1449            return NULL;
1450        }
1451        close(fd);
1452        buf[rc] = '\0';
1453        chptr = buf;
1454    
1455        char *foundanswer = NULL;
1456    
1457        while (chptr && chptr != buf+rc) {
1458            devname = chptr;
1459    
1460            /*
1461             * The first column of a mtab entry is the device, but if the entry is a
1462             * special device it won't start with /, so move on to the next line.
1463             */
1464            if (*devname != '/') {
1465                chptr = strchr(chptr, '\n');
1466                if (chptr)
1467                    chptr++;
1468                continue;
1469            }
1470    
1471            /* Seek to the next space */
1472            chptr = strchr(chptr, ' ');
1473            if (!chptr) {
1474                fprintf(stderr, "grubby: error parsing %s: %s\n",
1475                        _PATH_MOUNTED, strerror(errno));
1476                return NULL;
1477            }
1478    
1479            /*
1480             * The second column of a mtab entry is the mount point, we are looking
1481             * for '/' obviously.
1482             */
1483            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1484                /* remember the last / entry in mtab */
1485               foundanswer = devname;
1486            }
1487    
1488            /* Next line */
1489            chptr = strchr(chptr, '\n');
1490            if (chptr)
1491                chptr++;
1492        }
1493    
1494        /* Return the last / entry found */
1495        if (foundanswer) {
1496            chptr = strchr(foundanswer, ' ');
1497            *chptr = '\0';
1498            return strdup(foundanswer);
1499        }
1500    
1501        return NULL;
1502    }
1503    
1504    void printEntry(struct singleEntry * entry) {
1505        int i;
1506        struct singleLine * line;
1507    
1508        for (line = entry->lines; line; line = line->next) {
1509     fprintf(stderr, "DBG: %s", line->indent);
1510     for (i = 0; i < line->numElements; i++) {
1511        /* Need to handle this, because we strip the quotes from
1512         * menuentry when read it. */
1513        if (line->type == LT_MENUENTRY && i == 1) {
1514     if(!isquote(*line->elements[i].item))
1515        fprintf(stderr, "\'%s\'", line->elements[i].item);
1516     else
1517        fprintf(stderr, "%s", line->elements[i].item);
1518     fprintf(stderr, "%s", line->elements[i].indent);
1519    
1520     continue;
1521        }
1522        
1523        fprintf(stderr, "%s%s",
1524        line->elements[i].item, line->elements[i].indent);
1525     }
1526     fprintf(stderr, "\n");
1527        }
1528    }
1529    
1530    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1531    {
1532        va_list argp;
1533    
1534        if (!debug)
1535     return;
1536    
1537        va_start(argp, fmt);
1538        fprintf(stderr, "DBG: Image entry failed: ");
1539        vfprintf(stderr, fmt, argp);
1540        printEntry(entry);
1541        va_end(argp);
1542    }
1543    
1544    #define beginswith(s, c) ((s) && (s)[0] == (c))
1545    
1546    static int endswith(const char *s, char c)
1547    {
1548     int slen;
1549    
1550     if (!s || !s[0])
1551     return 0;
1552     slen = strlen(s) - 1;
1553    
1554     return s[slen] == c;
1555    }
1556    
1557  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1558    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1559      struct singleLine * line;      struct singleLine * line;
1560      char * fullName;      char * fullName;
1561      int i;      int i;
     struct stat sb, sb2;  
1562      char * dev;      char * dev;
     char * end;  
1563      char * rootspec;      char * rootspec;
1564        char * rootdev;
1565    
1566      line = entry->lines;      if (skipRemoved && entry->skip) {
1567      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1568         return 0;
1569      if (!line) return 0;      }
1570      if (skipRemoved && entry->skip) return 0;  
1571      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1572        if (!line) {
1573     notSuitablePrintf(entry, "no line found\n");
1574     return 0;
1575        }
1576        if (line->numElements < 2) {
1577     notSuitablePrintf(entry, "line has only %d elements\n",
1578        line->numElements);
1579     return 0;
1580        }
1581    
1582      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1583    
1584      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1585        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1586      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1587      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1588              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1589                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1590      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1591                line->elements[1].item + rootspec_offset);
1592        if (access(fullName, R_OK)) {
1593     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1594     return 0;
1595        }
1596      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1597   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1598      if (i < line->numElements) {      if (i < line->numElements) {
1599   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1600      } else {      } else {
1601   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1602   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1603    
1604   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1605      dev = line->elements[1].item;      dev = line->elements[1].item;
1606   } else {   } else {
1607              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1608      /* 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.
1609      line = entry->lines;       */
1610        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1611    
1612              /* failed to find one */              /* failed to find one */
1613              if (!line) return 0;              if (!line) {
1614     notSuitablePrintf(entry, "no line found\n");
1615     return 0;
1616                }
1617    
1618      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1619          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1620      if (i < line->numElements)      if (i < line->numElements)
1621          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1622      else {      else {
1623     notSuitablePrintf(entry, "no root= entry found\n");
1624   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1625          return 0;          return 0;
1626              }              }
1627   }   }
1628      }      }
1629    
1630      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1631   dev += 6;      if (!getpathbyspec(dev)) {
1632            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1633   /* check which device has this label */          return 0;
1634   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1635   if (!dev) return 0;   dev = getpathbyspec(dev);
1636    
1637        rootdev = findDiskForRoot();
1638        if (!rootdev) {
1639            notSuitablePrintf(entry, "can't find root device\n");
1640     return 0;
1641      }      }
1642    
1643      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1644   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1645      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1646      } else {          free(rootdev);
1647   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1648   if (*end) return 0;      }
1649    
1650        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1651            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1652     getuuidbydev(rootdev), getuuidbydev(dev));
1653     free(rootdev);
1654            return 0;
1655      }      }
     stat("/", &sb2);  
1656    
1657      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1658    
1659      return 1;      return 1;
1660  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1698  struct singleEntry * findEntryByPath(str
1698   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1699   if (!entry) return NULL;   if (!entry) return NULL;
1700    
1701   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1702   if (!line) return NULL;   if (!line) return NULL;
1703    
1704   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1736  struct singleEntry * findEntryByPath(str
1736    
1737   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1738      prefix = "";      prefix = "";
1739      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1740      kernel += 6;      kernel += 6;
1741   }   }
1742    
1743   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1744      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
   
1745    
1746      if (line && line->numElements >= 2 && !entry->skip) {      dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
                 rootspec = getRootSpecifier(line->elements[1].item);  
         if (!strcmp(line->elements[1].item  +  
                             ((rootspec != NULL) ? strlen(rootspec) : 0),  
                             kernel + strlen(prefix)))  
                     break;  
             }  
               
             /* have to check multiboot lines too */  
             if (entry->multiboot) {  
                 while (line && line->type != LT_MBMODULE) line = line->next;  
                 if (line && line->numElements >= 2 && !entry->skip) {  
                     rootspec = getRootSpecifier(line->elements[1].item);  
                     if (!strcmp(line->elements[1].item  +  
                                 ((rootspec != NULL) ? strlen(rootspec) : 0),  
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1747    
1748      i++;      /* check all the lines matching checkType */
1749        for (line = entry->lines; line; line = line->next) {
1750     line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1751         LT_KERNEL|LT_MBMODULE|LT_HYPER :
1752         checkType, line);
1753     if (!line) break;  /* not found in this entry */
1754    
1755     if (line && line->type != LT_MENUENTRY &&
1756     line->numElements >= 2) {
1757        rootspec = getRootSpecifier(line->elements[1].item);
1758        if (!strcmp(line->elements[1].item +
1759     ((rootspec != NULL) ? strlen(rootspec) : 0),
1760     kernel + strlen(prefix)))
1761     break;
1762     }
1763     if(line->type == LT_MENUENTRY &&
1764     !strcmp(line->elements[1].item, kernel))
1765        break;
1766        }
1767    
1768        /* make sure this entry has a kernel identifier; this skips
1769         * non-Linux boot entries (could find netbsd etc, though, which is
1770         * unfortunate)
1771         */
1772        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1773     break; /* found 'im! */
1774   }   }
1775    
1776   if (index) *index = i;   if (index) *index = i;
1777      }      }
1778    
     if (!entry) return NULL;  
   
     /* make sure this entry has a kernel identifier; this skips non-Linux  
        boot entries (could find netbsd etc, though, which is unfortunate) */  
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
     if (!line) {  
  if (!index) index = &i;  
  (*index)++;  
  return findEntryByPath(config, kernel, prefix, index);  
     }  
   
1779      return entry;      return entry;
1780  }  }
1781    
# Line 1200  void markRemovedImage(struct grubConfig Line 1854  void markRemovedImage(struct grubConfig
1854        const char * prefix) {        const char * prefix) {
1855      struct singleEntry * entry;      struct singleEntry * entry;
1856    
1857      if (!image) return;      if (!image)
1858     return;
1859    
1860        /* check and see if we're removing the default image */
1861        if (isdigit(*image)) {
1862     entry = findEntryByPath(cfg, image, prefix, NULL);
1863     if(entry)
1864        entry->skip = 1;
1865     return;
1866        }
1867    
1868      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1869   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1871  void markRemovedImage(struct grubConfig
1871    
1872  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1873       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1874       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1875      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1876      int i, j;      int i, j;
1877    
1878      if (newIsDefault) {      if (newIsDefault) {
1879   config->defaultImage = 0;   config->defaultImage = 0;
1880   return;   return;
1881        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1882     if (findEntryByIndex(config, index))
1883        config->defaultImage = index;
1884     else
1885        config->defaultImage = -1;
1886     return;
1887      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1888   i = 0;   i = 0;
1889   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1896  void setDefaultImage(struct grubConfig *
1896    
1897      /* 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
1898         changes */         changes */
1899      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1900     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1901        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1902        return;        return;
1903    
# Line 1286  void displayEntry(struct singleEntry * e Line 1956  void displayEntry(struct singleEntry * e
1956      char * root = NULL;      char * root = NULL;
1957      int i;      int i;
1958    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1959      printf("index=%d\n", index);      printf("index=%d\n", index);
1960    
1961      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1962        if (!line) {
1963            printf("non linux entry\n");
1964            return;
1965        }
1966    
1967        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
1968     printf("kernel=%s\n", line->elements[1].item);
1969        else
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);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2030        printf("initrd=");
2031     else
2032        printf("initrd=%s", prefix);
2033    
2034   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2035      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2036   printf("\n");   printf("\n");
2037      }      }
2038    
2039        line = getLineByType(LT_TITLE, entry->lines);
2040        if (line) {
2041     printf("title=%s\n", line->elements[1].item);
2042        } else {
2043     char * title;
2044     line = getLineByType(LT_MENUENTRY, entry->lines);
2045     title = grub2ExtractTitle(line);
2046     if (title)
2047        printf("title=%s\n", title);
2048        }
2049    }
2050    
2051    int isSuseSystem(void) {
2052        const char * path;
2053        const static char default_path[] = "/etc/SuSE-release";
2054    
2055        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2056     path = default_path;
2057    
2058        if (!access(path, R_OK))
2059     return 1;
2060        return 0;
2061    }
2062    
2063    int isSuseGrubConf(const char * path) {
2064        FILE * grubConf;
2065        char * line = NULL;
2066        size_t len = 0, res = 0;
2067    
2068        grubConf = fopen(path, "r");
2069        if (!grubConf) {
2070            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2071     return 0;
2072        }
2073    
2074        while ((res = getline(&line, &len, grubConf)) != -1) {
2075     if (!strncmp(line, "setup", 5)) {
2076        fclose(grubConf);
2077        free(line);
2078        return 1;
2079     }
2080        }
2081    
2082        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2083          path);
2084    
2085        fclose(grubConf);
2086        free(line);
2087        return 0;
2088    }
2089    
2090    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2091        FILE * grubConf;
2092        char * line = NULL;
2093        size_t res = 0, len = 0;
2094    
2095        if (!path) return 1;
2096        if (!lbaPtr) return 1;
2097    
2098        grubConf = fopen(path, "r");
2099        if (!grubConf) return 1;
2100    
2101        while ((res = getline(&line, &len, grubConf)) != -1) {
2102     if (line[res - 1] == '\n')
2103        line[res - 1] = '\0';
2104     else if (len > res)
2105        line[res] = '\0';
2106     else {
2107        line = realloc(line, res + 1);
2108        line[res] = '\0';
2109     }
2110    
2111     if (!strncmp(line, "setup", 5)) {
2112        if (strstr(line, "--force-lba")) {
2113            *lbaPtr = 1;
2114        } else {
2115            *lbaPtr = 0;
2116        }
2117        dbgPrintf("lba: %i\n", *lbaPtr);
2118        break;
2119     }
2120        }
2121    
2122        free(line);
2123        fclose(grubConf);
2124        return 0;
2125    }
2126    
2127    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2128        FILE * grubConf;
2129        char * line = NULL;
2130        size_t res = 0, len = 0;
2131        char * lastParamPtr = NULL;
2132        char * secLastParamPtr = NULL;
2133        char installDeviceNumber = '\0';
2134        char * bounds = NULL;
2135    
2136        if (!path) return 1;
2137        if (!devicePtr) return 1;
2138    
2139        grubConf = fopen(path, "r");
2140        if (!grubConf) return 1;
2141    
2142        while ((res = getline(&line, &len, grubConf)) != -1) {
2143     if (strncmp(line, "setup", 5))
2144        continue;
2145    
2146     if (line[res - 1] == '\n')
2147        line[res - 1] = '\0';
2148     else if (len > res)
2149        line[res] = '\0';
2150     else {
2151        line = realloc(line, res + 1);
2152        line[res] = '\0';
2153     }
2154    
2155     lastParamPtr = bounds = line + res;
2156    
2157     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2158     while (!isspace(*lastParamPtr))
2159        lastParamPtr--;
2160     lastParamPtr++;
2161    
2162     secLastParamPtr = lastParamPtr - 2;
2163     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2164    
2165     if (lastParamPtr + 3 > bounds) {
2166        dbgPrintf("lastParamPtr going over boundary");
2167        fclose(grubConf);
2168        free(line);
2169        return 1;
2170     }
2171     if (!strncmp(lastParamPtr, "(hd", 3))
2172        lastParamPtr += 3;
2173     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2174    
2175     /*
2176     * Second last parameter will decide wether last parameter is
2177     * an IMAGE_DEVICE or INSTALL_DEVICE
2178     */
2179     while (!isspace(*secLastParamPtr))
2180        secLastParamPtr--;
2181     secLastParamPtr++;
2182    
2183     if (secLastParamPtr + 3 > bounds) {
2184        dbgPrintf("secLastParamPtr going over boundary");
2185        fclose(grubConf);
2186        free(line);
2187        return 1;
2188     }
2189     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2190     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2191        secLastParamPtr += 3;
2192        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2193        installDeviceNumber = *secLastParamPtr;
2194     } else {
2195        installDeviceNumber = *lastParamPtr;
2196     }
2197    
2198     *devicePtr = malloc(6);
2199     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2200     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2201     fclose(grubConf);
2202     free(line);
2203     return 0;
2204        }
2205    
2206        free(line);
2207        fclose(grubConf);
2208        return 1;
2209    }
2210    
2211    int grubGetBootFromDeviceMap(const char * device,
2212         char ** bootPtr) {
2213        FILE * deviceMap;
2214        char * line = NULL;
2215        size_t res = 0, len = 0;
2216        char * devicePtr;
2217        char * bounds = NULL;
2218        const char * path;
2219        const static char default_path[] = "/boot/grub/device.map";
2220    
2221        if (!device) return 1;
2222        if (!bootPtr) return 1;
2223    
2224        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2225     path = default_path;
2226    
2227        dbgPrintf("opening grub device.map file from: %s\n", path);
2228        deviceMap = fopen(path, "r");
2229        if (!deviceMap)
2230     return 1;
2231    
2232        while ((res = getline(&line, &len, deviceMap)) != -1) {
2233            if (!strncmp(line, "#", 1))
2234        continue;
2235    
2236     if (line[res - 1] == '\n')
2237        line[res - 1] = '\0';
2238     else if (len > res)
2239        line[res] = '\0';
2240     else {
2241        line = realloc(line, res + 1);
2242        line[res] = '\0';
2243     }
2244    
2245     devicePtr = line;
2246     bounds = line + res;
2247    
2248     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2249        devicePtr++;
2250     dbgPrintf("device: %s\n", devicePtr);
2251    
2252     if (!strncmp(devicePtr, device, strlen(device))) {
2253        devicePtr += strlen(device);
2254        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2255            devicePtr++;
2256    
2257        *bootPtr = strdup(devicePtr);
2258        break;
2259     }
2260        }
2261    
2262        free(line);
2263        fclose(deviceMap);
2264        return 0;
2265    }
2266    
2267    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2268        char * grubDevice;
2269    
2270        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2271     dbgPrintf("error looking for grub installation device\n");
2272        else
2273     dbgPrintf("grubby installation device: %s\n", grubDevice);
2274    
2275        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2276     dbgPrintf("error looking for grub boot device\n");
2277        else
2278     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2279    
2280        free(grubDevice);
2281        return 0;
2282    }
2283    
2284    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2285        /*
2286         * This SuSE grub configuration file at this location is not your average
2287         * grub configuration file, but instead the grub commands used to setup
2288         * grub on that system.
2289         */
2290        const char * path;
2291        const static char default_path[] = "/etc/grub.conf";
2292    
2293        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2294     path = default_path;
2295    
2296        if (!isSuseGrubConf(path)) return 1;
2297    
2298        if (lbaPtr) {
2299            *lbaPtr = 0;
2300            if (suseGrubConfGetLba(path, lbaPtr))
2301                return 1;
2302        }
2303    
2304        if (bootPtr) {
2305            *bootPtr = NULL;
2306            suseGrubConfGetBoot(path, bootPtr);
2307        }
2308    
2309        return 0;
2310  }  }
2311    
2312  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2316  int parseSysconfigGrub(int * lbaPtr, cha
2316      char * start;      char * start;
2317      char * param;      char * param;
2318    
2319      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2320      if (!in) return 1;      if (!in) return 1;
2321    
2322      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2357  int parseSysconfigGrub(int * lbaPtr, cha
2357  }  }
2358    
2359  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2360      char * boot;      char * boot = NULL;
2361      int lba;      int lba;
2362    
2363      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2364   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2365   if (boot) printf("boot=%s\n", boot);      free(boot);
2366        return;
2367     }
2368        } else {
2369            if (parseSysconfigGrub(&lba, &boot)) {
2370        free(boot);
2371        return;
2372     }
2373        }
2374    
2375        if (lba) printf("lba\n");
2376        if (boot) {
2377     printf("boot=%s\n", boot);
2378     free(boot);
2379      }      }
2380  }  }
2381    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2391  int displayInfo(struct grubConfig * conf
2391   return 1;   return 1;
2392      }      }
2393    
2394      /* 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
2395         be a better way */         be a better way */
2396      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2397   dumpSysconfigGrub();   dumpSysconfigGrub();
2398      } else {      } else {
2399   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2400   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2401      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2402   }   }
2403    
2404   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2405   if (line) printf("lba\n");   if (line) printf("lba\n");
2406      }      }
2407    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2416  int displayInfo(struct grubConfig * conf
2416      return 0;      return 0;
2417  }  }
2418    
2419    struct singleLine * addLineTmpl(struct singleEntry * entry,
2420     struct singleLine * tmplLine,
2421     struct singleLine * prevLine,
2422     const char * val,
2423     struct configFileInfo * cfi)
2424    {
2425        struct singleLine * newLine = lineDup(tmplLine);
2426    
2427        if (val) {
2428     /* override the inherited value with our own.
2429     * This is a little weak because it only applies to elements[1]
2430     */
2431     if (newLine->numElements > 1)
2432        removeElement(newLine, 1);
2433     insertElement(newLine, val, 1, cfi);
2434    
2435     /* but try to keep the rootspec from the template... sigh */
2436     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2437        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2438        if (rootspec != NULL) {
2439     free(newLine->elements[1].item);
2440     newLine->elements[1].item =
2441        sdupprintf("%s%s", rootspec, val);
2442        }
2443     }
2444        }
2445    
2446        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2447          newLine->elements[0].item : "");
2448    
2449        if (!entry->lines) {
2450     /* first one on the list */
2451     entry->lines = newLine;
2452        } else if (prevLine) {
2453     /* add after prevLine */
2454     newLine->next = prevLine->next;
2455     prevLine->next = newLine;
2456        }
2457    
2458        return newLine;
2459    }
2460    
2461  /* val may be NULL */  /* val may be NULL */
2462  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2463       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2464       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2465       char * val) {       const char * val) {
2466      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2467      int i;      struct keywordTypes * kw;
2468        struct singleLine tmpl;
2469    
2470      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2471   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2472      if (type != LT_TITLE || !cfi->titleBracketed)       */
2473          if (!cfi->keywords[i].key) abort();  
2474        if (type == LT_TITLE && cfi->titleBracketed) {
2475     /* we're doing a bracketed title (zipl) */
2476     tmpl.type = type;
2477     tmpl.numElements = 1;
2478     tmpl.elements = alloca(sizeof(*tmpl.elements));
2479     tmpl.elements[0].item = alloca(strlen(val)+3);
2480     sprintf(tmpl.elements[0].item, "[%s]", val);
2481     tmpl.elements[0].indent = "";
2482     val = NULL;
2483        } else if (type == LT_MENUENTRY) {
2484     char *lineend = "--class gnu-linux --class gnu --class os {";
2485     if (!val) {
2486        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2487        abort();
2488     }
2489     kw = getKeywordByType(type, cfi);
2490     if (!kw) {
2491        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2492        abort();
2493     }
2494     tmpl.indent = "";
2495     tmpl.type = type;
2496     tmpl.numElements = 3;
2497     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2498     tmpl.elements[0].item = kw->key;
2499     tmpl.elements[0].indent = alloca(2);
2500     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2501     tmpl.elements[1].item = (char *)val;
2502     tmpl.elements[1].indent = alloca(2);
2503     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2504     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2505     strcpy(tmpl.elements[2].item, lineend);
2506     tmpl.elements[2].indent = "";
2507        } else {
2508     kw = getKeywordByType(type, cfi);
2509     if (!kw) {
2510        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2511        abort();
2512     }
2513     tmpl.type = type;
2514     tmpl.numElements = val ? 2 : 1;
2515     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2516     tmpl.elements[0].item = kw->key;
2517     tmpl.elements[0].indent = alloca(2);
2518     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2519     if (val) {
2520        tmpl.elements[1].item = (char *)val;
2521        tmpl.elements[1].indent = "";
2522     }
2523        }
2524    
2525      /* 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
2526         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2527         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
2528         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2529         differently from the rest) */         differently from the rest) */
2530      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2531   line = entry->lines;   if (line->numElements) prev = line;
2532   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2533   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;  
2534      }      }
2535    
2536      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2537          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2538          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2539          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2540          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2541          line->elements[0].indent = malloc(2);   else
2542          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2543          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2544             if (menuEntry)
2545          if (val) {      tmpl.indent = "\t";
2546              line->elements[1].item = val;   else if (prev == entry->lines)
2547              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2548          }   else
2549      } 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("");  
2550      }      }
2551    
2552      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2553  }  }
2554    
2555  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2574  void removeLine(struct singleEntry * ent
2574      free(line);      free(line);
2575  }  }
2576    
2577    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2578    {
2579        struct singleLine newLine = {
2580     .indent = tmplLine->indent,
2581     .type = tmplLine->type,
2582     .next = tmplLine->next,
2583        };
2584        int firstQuotedItem = -1;
2585        int quoteLen = 0;
2586        int j;
2587        int element = 0;
2588        char *c;
2589    
2590        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2591        strcpy(c, tmplLine->elements[0].item);
2592        insertElement(&newLine, c, element++, cfi);
2593        free(c);
2594        c = NULL;
2595    
2596        for (j = 1; j < tmplLine->numElements; j++) {
2597     if (firstQuotedItem == -1) {
2598        quoteLen += strlen(tmplLine->elements[j].item);
2599        
2600        if (isquote(tmplLine->elements[j].item[0])) {
2601     firstQuotedItem = j;
2602            quoteLen += strlen(tmplLine->elements[j].indent);
2603        } else {
2604     c = malloc(quoteLen + 1);
2605     strcpy(c, tmplLine->elements[j].item);
2606     insertElement(&newLine, c, element++, cfi);
2607     free(c);
2608     quoteLen = 0;
2609        }
2610     } else {
2611        int itemlen = strlen(tmplLine->elements[j].item);
2612        quoteLen += itemlen;
2613        quoteLen += strlen(tmplLine->elements[j].indent);
2614        
2615        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2616     c = malloc(quoteLen + 1);
2617     c[0] = '\0';
2618     for (int i = firstQuotedItem; i < j+1; i++) {
2619        strcat(c, tmplLine->elements[i].item);
2620        strcat(c, tmplLine->elements[i].indent);
2621     }
2622     insertElement(&newLine, c, element++, cfi);
2623     free(c);
2624    
2625     firstQuotedItem = -1;
2626     quoteLen = 0;
2627        }
2628     }
2629        }
2630        while (tmplLine->numElements)
2631     removeElement(tmplLine, 0);
2632        if (tmplLine->elements)
2633     free(tmplLine->elements);
2634    
2635        tmplLine->numElements = newLine.numElements;
2636        tmplLine->elements = newLine.elements;
2637    }
2638    
2639    static void insertElement(struct singleLine * line,
2640      const char * item, int insertHere,
2641      struct configFileInfo * cfi)
2642    {
2643        struct keywordTypes * kw;
2644        char indent[2] = "";
2645    
2646        /* sanity check */
2647        if (insertHere > line->numElements) {
2648     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2649      insertHere, line->numElements);
2650     insertHere = line->numElements;
2651        }
2652    
2653        line->elements = realloc(line->elements, (line->numElements + 1) *
2654         sizeof(*line->elements));
2655        memmove(&line->elements[insertHere+1],
2656        &line->elements[insertHere],
2657        (line->numElements - insertHere) *
2658        sizeof(*line->elements));
2659        line->elements[insertHere].item = strdup(item);
2660    
2661        kw = getKeywordByType(line->type, cfi);
2662    
2663        if (line->numElements == 0) {
2664     indent[0] = '\0';
2665        } else if (insertHere == 0) {
2666     indent[0] = kw->nextChar;
2667        } else if (kw->separatorChar != '\0') {
2668     indent[0] = kw->separatorChar;
2669        } else {
2670     indent[0] = ' ';
2671        }
2672    
2673        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2674     /* move the end-of-line forward */
2675     line->elements[insertHere].indent =
2676        line->elements[insertHere-1].indent;
2677     line->elements[insertHere-1].indent = strdup(indent);
2678        } else {
2679     line->elements[insertHere].indent = strdup(indent);
2680        }
2681    
2682        line->numElements++;
2683    
2684        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2685          line->elements[0].item,
2686          line->elements[insertHere].item,
2687          line->elements[insertHere].indent,
2688          insertHere);
2689    }
2690    
2691    static void removeElement(struct singleLine * line, int removeHere) {
2692        int i;
2693    
2694        /* sanity check */
2695        if (removeHere >= line->numElements) return;
2696    
2697        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2698          removeHere, line->elements[removeHere].item);
2699    
2700        free(line->elements[removeHere].item);
2701    
2702        if (removeHere > 1) {
2703     /* previous argument gets this argument's post-indentation */
2704     free(line->elements[removeHere-1].indent);
2705     line->elements[removeHere-1].indent =
2706        line->elements[removeHere].indent;
2707        } else {
2708     free(line->elements[removeHere].indent);
2709        }
2710    
2711        /* now collapse the array, but don't bother to realloc smaller */
2712        for (i = removeHere; i < line->numElements - 1; i++)
2713     line->elements[i] = line->elements[i + 1];
2714    
2715        line->numElements--;
2716    }
2717    
2718  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2719      char * first, * second;      char * first, * second;
2720      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2737  int updateActualImage(struct grubConfig
2737      struct singleEntry * entry;      struct singleEntry * entry;
2738      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2739      int index = 0;      int index = 0;
2740      int i, j, k;      int i, k;
2741      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2742      const char ** arg;      const char ** arg;
2743      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2744      int firstElement;      int firstElement;
2745      int *usedElements, *usedArgs;      int *usedElements;
2746        int doreplace;
2747    
2748      if (!image) return 0;      if (!image) return 0;
2749    
# Line 1609  int updateActualImage(struct grubConfig Line 2770  int updateActualImage(struct grubConfig
2770   }   }
2771      }      }
2772    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2773    
2774      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2775   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2776    
2777      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2778   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2779    
2780      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2781    
2782      k = 0;   if (multibootArgs && !entry->multiboot)
2783      for (arg = newArgs; *arg; arg++)      continue;
2784          k++;  
2785      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2786     * LT_KERNELARGS, use that.  Otherwise use
2787     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2788     */
2789     if (useKernelArgs) {
2790        line = getLineByType(LT_KERNELARGS, entry->lines);
2791        if (!line) {
2792     /* no LT_KERNELARGS, need to add it */
2793     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2794           cfg->secondaryIndent, NULL);
2795        }
2796        firstElement = 1;
2797    
2798      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2799   index++;      line = getLineByType(LT_HYPER, entry->lines);
2800        if (!line) {
2801     /* a multiboot entry without LT_HYPER? */
2802     continue;
2803        }
2804        firstElement = 2;
2805    
2806   line = entry->lines;   } else {
2807   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2808   if (!line) continue;      if (!line) {
2809   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2810     continue;
2811          if (entry->multiboot && !multibootArgs) {      }
2812              /* 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;  
2813   }   }
2814    
2815   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2816      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2817      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2818     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2819        /* this is a multiboot entry, make sure there's
2820         * -- on the args line
2821         */
2822        for (i = firstElement; i < line->numElements; i++) {
2823     if (!strcmp(line->elements[i].item, "--"))
2824        break;
2825        }
2826        if (i == line->numElements) {
2827     /* assume all existing args are kernel args,
2828     * prepend -- to make it official
2829     */
2830     insertElement(line, "--", firstElement, cfg->cfi);
2831     i = firstElement;
2832        }
2833        if (!multibootArgs) {
2834     /* kernel args start after the -- */
2835     firstElement = i + 1;
2836        }
2837     } else if (cfg->cfi->mbConcatArgs) {
2838        /* this is a non-multiboot entry, remove hyper args */
2839        for (i = firstElement; i < line->numElements; i++) {
2840     if (!strcmp(line->elements[i].item, "--"))
2841        break;
2842        }
2843        if (i < line->numElements) {
2844     /* remove args up to -- */
2845     while (strcmp(line->elements[firstElement].item, "--"))
2846        removeElement(line, firstElement);
2847     /* remove -- */
2848     removeElement(line, firstElement);
2849        }
2850   }   }
2851    
2852          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2853    
2854          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2855   for (arg = newArgs; *arg; arg++) {  
2856              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2857      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2858     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2859        !strcmp(line->elements[i].item, "--"))
2860     {
2861        /* reached the end of hyper args, insert here */
2862        doreplace = 0;
2863        break;  
2864     }
2865                  if (usedElements[i])                  if (usedElements[i])
2866                      continue;                      continue;
2867   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2868                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2869      break;      break;
2870                  }                  }
2871              }              }
     chptr = strchr(*arg, '=');  
2872    
2873      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2874   /* replace */   /* direct replacement */
2875   free(line->elements[i].item);   free(line->elements[i].item);
2876   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("");  
  }  
2877    
2878   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2879   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2880      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2881   /* append */   if (rootLine) {
2882   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2883   (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(" ");  
2884   } else {   } else {
2885      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2886         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2887   }   }
2888        }
2889    
2890   line->numElements++;      else {
2891     /* insert/append */
2892     insertElement(line, *arg, i, cfg->cfi);
2893     usedElements = realloc(usedElements, line->numElements *
2894           sizeof(*usedElements));
2895     memmove(&usedElements[i + 1], &usedElements[i],
2896     line->numElements - i - 1);
2897     usedElements[i] = 1;
2898    
2899   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2900     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2901     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2902   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2903      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2904      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2905   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2906   }   }
2907      }      }
             k++;  
2908   }   }
2909    
2910          free(usedElements);          free(usedElements);
2911    
  /* 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? */  
2912   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2913      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2914   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2915        !strcmp(line->elements[i].item, "--"))
2916        /* reached the end of hyper args, stop here */
2917        break;
2918     if (!argMatch(line->elements[i].item, *arg)) {
2919        removeElement(line, i);
2920      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;  
2921   }   }
2922        }
2923   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2924        if (useRoot && !strncmp(*arg, "root=", 5)) {
2925   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2926      line->elements[j - 1] = line->elements[j];   if (rootLine)
2927        removeLine(entry, rootLine);
  line->numElements--;  
2928      }      }
2929   }   }
2930    
# Line 1760  int updateActualImage(struct grubConfig Line 2935  int updateActualImage(struct grubConfig
2935   }   }
2936      }      }
2937    
     free(usedArgs);  
2938      free(newArgs);      free(newArgs);
2939      free(oldArgs);      free(oldArgs);
2940    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2960  int updateImage(struct grubConfig * cfg,
2960      return rc;      return rc;
2961  }  }
2962    
2963    int updateInitrd(struct grubConfig * cfg, const char * image,
2964                     const char * prefix, const char * initrd) {
2965        struct singleEntry * entry;
2966        struct singleLine * line, * kernelLine, *endLine = NULL;
2967        int index = 0;
2968    
2969        if (!image) return 0;
2970    
2971        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2972            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2973            if (!kernelLine) continue;
2974    
2975            line = getLineByType(LT_INITRD, entry->lines);
2976            if (line)
2977                removeLine(entry, line);
2978            if (prefix) {
2979                int prefixLen = strlen(prefix);
2980                if (!strncmp(initrd, prefix, prefixLen))
2981                    initrd += prefixLen;
2982            }
2983     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2984     if (endLine)
2985        removeLine(entry, endLine);
2986            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2987            if (!line)
2988        return 1;
2989     if (endLine) {
2990        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2991                if (!line)
2992     return 1;
2993     }
2994    
2995            break;
2996        }
2997    
2998        return 0;
2999    }
3000    
3001  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3002      int fd;      int fd;
3003      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3021  int checkDeviceBootloader(const char * d
3021      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3022   return 0;   return 0;
3023    
3024      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3025   offset = boot[2] + 2;   offset = boot[2] + 2;
3026      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3027   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3028      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3029   offset = boot[1] + 2;        offset = boot[1] + 2;
3030            /*
3031     * it looks like grub, when copying stage1 into the mbr, patches stage1
3032     * right after the JMP location, replacing other instructions such as
3033     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3034     * different bytes.
3035     */
3036          if ((bootSect[offset + 1] == NOOP_OPCODE)
3037      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3038     offset = offset + 3;
3039          }
3040      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3041   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3042      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3178  int checkForLilo(struct grubConfig * con
3178      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3179  }  }
3180    
3181    int checkForGrub2(struct grubConfig * config) {
3182        if (!access("/etc/grub.d/", R_OK))
3183     return 2;
3184    
3185        return 1;
3186    }
3187    
3188  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3189      int fd;      int fd;
3190      unsigned char bootSect[512];      unsigned char bootSect[512];
3191      char * boot;      char * boot;
3192        int onSuse = isSuseSystem();
3193    
3194      if (parseSysconfigGrub(NULL, &boot))  
3195   return 0;      if (onSuse) {
3196     if (parseSuseGrubConf(NULL, &boot))
3197        return 0;
3198        } else {
3199     if (parseSysconfigGrub(NULL, &boot))
3200        return 0;
3201        }
3202    
3203      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3204      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3212  int checkForGrub(struct grubConfig * con
3212      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3213   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3214   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3215     close(fd);
3216   return 1;   return 1;
3217      }      }
3218      close(fd);      close(fd);
3219    
3220        /* The more elaborate checks do not work on SuSE. The checks done
3221         * seem to be reasonble (at least for now), so just return success
3222         */
3223        if (onSuse)
3224     return 2;
3225    
3226      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3227  }  }
3228    
3229    int checkForExtLinux(struct grubConfig * config) {
3230        int fd;
3231        unsigned char bootSect[512];
3232        char * boot;
3233        char executable[] = "/boot/extlinux/extlinux";
3234    
3235        printf("entered: checkForExtLinux()\n");
3236    
3237        if (parseSysconfigGrub(NULL, &boot))
3238     return 0;
3239    
3240        /* assume grub is not installed -- not an error condition */
3241        if (!boot)
3242     return 0;
3243    
3244        fd = open(executable, O_RDONLY);
3245        if (fd < 0)
3246     /* this doesn't exist if grub hasn't been installed */
3247     return 0;
3248    
3249        if (read(fd, bootSect, 512) != 512) {
3250     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3251     executable, strerror(errno));
3252     return 1;
3253        }
3254        close(fd);
3255    
3256        return checkDeviceBootloader(boot, bootSect);
3257    }
3258    
3259    int checkForYaboot(struct grubConfig * config) {
3260        /*
3261         * This is a simplistic check that we consider good enough for own puporses
3262         *
3263         * If we were to properly check if yaboot is *installed* we'd need to:
3264         * 1) get the system boot device (LT_BOOT)
3265         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3266         *    the content on the boot device
3267         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3268         * 4) check again if binary and boot device contents match
3269         */
3270        if (!access("/etc/yaboot.conf", R_OK))
3271     return 2;
3272    
3273        return 1;
3274    }
3275    
3276    int checkForElilo(struct grubConfig * config) {
3277        if (!access("/etc/elilo.conf", R_OK))
3278     return 2;
3279    
3280        return 1;
3281    }
3282    
3283  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3284      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3285    
# Line 1994  static char * getRootSpecifier(char * st Line 3291  static char * getRootSpecifier(char * st
3291      return rootspec;      return rootspec;
3292  }  }
3293    
3294    static char * getInitrdVal(struct grubConfig * config,
3295       const char * prefix, struct singleLine *tmplLine,
3296       const char * newKernelInitrd,
3297       const char ** extraInitrds, int extraInitrdCount)
3298    {
3299        char *initrdVal, *end;
3300        int i;
3301        size_t totalSize;
3302        size_t prefixLen;
3303        char separatorChar;
3304    
3305        prefixLen = strlen(prefix);
3306        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3307    
3308        for (i = 0; i < extraInitrdCount; i++) {
3309     totalSize += sizeof(separatorChar);
3310     totalSize += strlen(extraInitrds[i]) - prefixLen;
3311        }
3312    
3313        initrdVal = end = malloc(totalSize);
3314    
3315        end = stpcpy (end, newKernelInitrd + prefixLen);
3316    
3317        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3318        for (i = 0; i < extraInitrdCount; i++) {
3319     const char *extraInitrd;
3320     int j;
3321    
3322     extraInitrd = extraInitrds[i] + prefixLen;
3323     /* Don't add entries that are already there */
3324     if (tmplLine != NULL) {
3325        for (j = 2; j < tmplLine->numElements; j++)
3326     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3327        break;
3328    
3329        if (j != tmplLine->numElements)
3330     continue;
3331     }
3332    
3333     *end++ = separatorChar;
3334     end = stpcpy(end, extraInitrd);
3335        }
3336    
3337        return initrdVal;
3338    }
3339    
3340  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3341           const char * prefix,           const char * prefix,
3342   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3343   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3344                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3345                     const char * newMBKernel, const char * newMBKernelArgs) {
3346      struct singleEntry * new;      struct singleEntry * new;
3347      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3348      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3349      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3350    
3351      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3352    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3376  int addNewKernel(struct grubConfig * con
3376      config->entries = new;      config->entries = new;
3377    
3378      /* copy/update from the template */      /* copy/update from the template */
3379      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3380        if (newKernelInitrd)
3381     needs |= NEED_INITRD;
3382      if (newMBKernel) {      if (newMBKernel) {
3383          needs |= KERNEL_MB;          needs |= NEED_MB;
3384          new->multiboot = 1;          new->multiboot = 1;
3385      }      }
3386    
3387      if (template) {      if (template) {
3388   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3389      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3390      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3391   indent = tmplLine->indent;   {
3392        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3393    
3394      /* skip comments */      /* skip comments */
3395      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3396      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3397      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3398    
3399      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3400      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3401     if (!template->multiboot && (needs & NEED_MB)) {
3402              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3403                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3404                  struct singleLine *l;       * hypervisor at the same time.
3405                  needs &= ~ KERNEL_MB;       */
3406        if (config->cfi->mbHyperFirst) {
3407                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3408                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3409                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3410                      newMBKernel + strlen(prefix));
3411                  tmplLine = lastLine;   /* set up for adding the kernel line */
3412                  if (!new->lines) {   free(tmplLine->indent);
3413                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3414                  } else {   needs &= ~NEED_MB;
3415                      newLine->next = l;      }
3416                      newLine = l;      if (needs & NEED_KERNEL) {
3417                  }   /* use addLineTmpl to preserve line elements,
3418                  continue;   * otherwise we could just call addLine.  Unfortunately
3419              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3420                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3421                  continue; /* don't need multiboot kernel here */   * change below.
3422              }   */
3423     struct keywordTypes * mbm_kw =
3424        getKeywordByType(LT_MBMODULE, config->cfi);
3425     if (mbm_kw) {
3426        tmplLine->type = LT_MBMODULE;
3427        free(tmplLine->elements[0].item);
3428        tmplLine->elements[0].item = strdup(mbm_kw->key);
3429     }
3430     newLine = addLineTmpl(new, tmplLine, newLine,
3431          newKernelPath + strlen(prefix), config->cfi);
3432     needs &= ~NEED_KERNEL;
3433        }
3434        if (needs & NEED_MB) { /* !mbHyperFirst */
3435     newLine = addLine(new, config->cfi, LT_HYPER,
3436      config->secondaryIndent,
3437      newMBKernel + strlen(prefix));
3438     needs &= ~NEED_MB;
3439        }
3440     } else if (needs & NEED_KERNEL) {
3441        newLine = addLineTmpl(new, tmplLine, newLine,
3442      newKernelPath + strlen(prefix), config->cfi);
3443        needs &= ~NEED_KERNEL;
3444     }
3445    
3446      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3447   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3448   new->lines = newLine;   if (needs & NEED_MB) {
3449      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3450   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3451   newLine = newLine->next;      needs &= ~NEED_MB;
3452      }   }
3453    
3454        } else if (tmplLine->type == LT_MBMODULE &&
3455           tmplLine->numElements >= 2) {
3456     if (new->multiboot) {
3457        if (needs & NEED_KERNEL) {
3458     newLine = addLineTmpl(new, tmplLine, newLine,
3459          newKernelPath +
3460          strlen(prefix), config->cfi);
3461     needs &= ~NEED_KERNEL;
3462        } else if (config->cfi->mbInitRdIsModule &&
3463           (needs & NEED_INITRD)) {
3464     char *initrdVal;
3465     initrdVal = getInitrdVal(config, prefix, tmplLine,
3466     newKernelInitrd, extraInitrds,
3467     extraInitrdCount);
3468     newLine = addLineTmpl(new, tmplLine, newLine,
3469          initrdVal, config->cfi);
3470     free(initrdVal);
3471     needs &= ~NEED_INITRD;
3472        }
3473     } else if (needs & NEED_KERNEL) {
3474        /* template is multi but new is not,
3475         * insert the kernel in the first module slot
3476         */
3477        tmplLine->type = LT_KERNEL;
3478        free(tmplLine->elements[0].item);
3479        tmplLine->elements[0].item =
3480     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3481        newLine = addLineTmpl(new, tmplLine, newLine,
3482      newKernelPath + strlen(prefix), config->cfi);
3483        needs &= ~NEED_KERNEL;
3484     } else if (needs & NEED_INITRD) {
3485        char *initrdVal;
3486        /* template is multi but new is not,
3487         * insert the initrd in the second module slot
3488         */
3489        tmplLine->type = LT_INITRD;
3490        free(tmplLine->elements[0].item);
3491        tmplLine->elements[0].item =
3492     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3493        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3494        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3495        free(initrdVal);
3496        needs &= ~NEED_INITRD;
3497     }
3498    
     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));  
                 }  
3499      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3500      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3501   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3502   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3503                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3504                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3505                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3506                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3507                  }       */
3508                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3509                  if (rootspec != NULL) {   char *initrdVal;
3510                      newLine->elements[1].item = sdupprintf("%s%s",  
3511                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3512                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3513                                                             strlen(prefix));    config->secondaryIndent,
3514                  } else {    initrdVal);
3515                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3516                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3517                  }      }
3518              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3519                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3520   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3521                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3522                      free(newLine->elements[0].item);      free(initrdVal);
3523                      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);  
3524   }   }
3525    
3526   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3527   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3528   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3529     char *nkt = malloc(strlen(newKernelTitle)+3);
3530     strcpy(nkt, "'");
3531     strcat(nkt, newKernelTitle);
3532     strcat(nkt, "'");
3533     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3534     free(nkt);
3535     needs &= ~NEED_TITLE;
3536      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3537                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3538                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3539                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3540                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3541                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3542                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3543                                             newLine->numElements);     config->cfi->titleBracketed) {
3544        /* addLineTmpl doesn't handle titleBracketed */
3545                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3546                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3547                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3548                  newLine->numElements = 1;   }
3549              }      } else if (tmplLine->type == LT_ECHO) {
3550        requote(tmplLine, config->cfi);
3551        static const char *prefix = "'Loading ";
3552        if (tmplLine->numElements > 1 &&
3553        strstr(tmplLine->elements[1].item, prefix) &&
3554        masterLine->next && masterLine->next->type == LT_KERNEL) {
3555     char *newTitle = malloc(strlen(prefix) +
3556     strlen(newKernelTitle) + 2);
3557    
3558     strcpy(newTitle, prefix);
3559     strcat(newTitle, newKernelTitle);
3560     strcat(newTitle, "'");
3561     newLine = addLine(new, config->cfi, LT_ECHO,
3562     tmplLine->indent, newTitle);
3563     free(newTitle);
3564        } else {
3565     /* pass through other lines from the template */
3566     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3567     config->cfi);
3568        }
3569        } else {
3570     /* pass through other lines from the template */
3571     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3572        }
3573   }   }
3574    
3575      } else {      } else {
3576   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3577      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3578     */
3579     switch (config->cfi->entryStart) {
3580        case LT_KERNEL:
3581     if (new->multiboot && config->cfi->mbHyperFirst) {
3582        /* fall through to LT_HYPER */
3583     } else {
3584        newLine = addLine(new, config->cfi, LT_KERNEL,
3585          config->primaryIndent,
3586          newKernelPath + strlen(prefix));
3587        needs &= ~NEED_KERNEL;
3588        break;
3589     }
3590    
3591        case LT_HYPER:
3592     newLine = addLine(new, config->cfi, LT_HYPER,
3593      config->primaryIndent,
3594      newMBKernel + strlen(prefix));
3595     needs &= ~NEED_MB;
3596   break;   break;
         }  
3597    
3598   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3599      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3600       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3601       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3602      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3603       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3604      default:        config->primaryIndent, nkt);
3605                  /* zipl strikes again */   free(nkt);
3606                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3607                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3608                      chptr = newKernelTitle;   break;
3609                      type = LT_TITLE;      }
3610                      break;      case LT_TITLE:
3611                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3612                      abort();   char * templabel;
3613                  }   int x = 0, y = 0;
3614   }  
3615     templabel = strdup(newKernelTitle);
3616     while( templabel[x]){
3617     if( templabel[x] == ' ' ){
3618     y = x;
3619     while( templabel[y] ){
3620     templabel[y] = templabel[y+1];
3621     y++;
3622     }
3623     }
3624     x++;
3625     }
3626     newLine = addLine(new, config->cfi, LT_TITLE,
3627      config->primaryIndent, templabel);
3628     free(templabel);
3629     }else{
3630     newLine = addLine(new, config->cfi, LT_TITLE,
3631      config->primaryIndent, newKernelTitle);
3632     }
3633     needs &= ~NEED_TITLE;
3634     break;
3635    
3636   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3637   new->lines = newLine;   abort();
3638     }
3639      }      }
3640    
3641      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3642          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3643              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3644                                config->secondaryIndent,       */
3645                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3646          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3647              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3648                                config->secondaryIndent,    newKernelTitle);
3649                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3650          /* don't need to check for title as it's guaranteed to have been      }
3651           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3652           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3653          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3654              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3655                                config->secondaryIndent,   needs &= ~NEED_MB;
3656                                newKernelInitrd + strlen(prefix));      }
3657      } else {      if (needs & NEED_KERNEL) {
3658          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3659              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3660                                config->secondaryIndent,        config->cfi)) ?
3661                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3662          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3663              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3664                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3665                                newKernelTitle);      }
3666          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3667              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3668                                config->secondaryIndent,    config->secondaryIndent,
3669                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3670     needs &= ~NEED_MB;
3671        }
3672        if (needs & NEED_INITRD) {
3673     char *initrdVal;
3674     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3675     newLine = addLine(new, config->cfi,
3676      (new->multiboot && getKeywordByType(LT_MBMODULE,
3677          config->cfi)) ?
3678      LT_MBMODULE : LT_INITRD,
3679      config->secondaryIndent,
3680      initrdVal);
3681     free(initrdVal);
3682     needs &= ~NEED_INITRD;
3683        }
3684        if (needs & NEED_END) {
3685     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3686     config->secondaryIndent, NULL);
3687     needs &= ~NEED_END;
3688        }
3689    
3690        if (needs) {
3691     printf(_("grubby: needs=%d, aborting\n"), needs);
3692     abort();
3693      }      }
3694    
3695      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3698  int addNewKernel(struct grubConfig * con
3698      return 0;      return 0;
3699  }  }
3700    
3701    static void traceback(int signum)
3702    {
3703        void *array[40];
3704        size_t size;
3705    
3706        signal(SIGSEGV, SIG_DFL);
3707        memset(array, '\0', sizeof (array));
3708        size = backtrace(array, 40);
3709    
3710        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3711                (unsigned long)size);
3712        backtrace_symbols_fd(array, size, STDERR_FILENO);
3713        exit(1);
3714    }
3715    
3716  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3717      poptContext optCon;      poptContext optCon;
3718      char * grubConfig = NULL;      const char * grubConfig = NULL;
3719      char * outputFile = NULL;      char * outputFile = NULL;
3720      int arg = 0;      int arg = 0;
3721      int flags = 0;      int flags = 0;
3722      int badImageOkay = 0;      int badImageOkay = 0;
3723        int configureGrub2 = 0;
3724      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3725      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3726        int configureExtLinux = 0;
3727      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3728        int extraInitrdCount = 0;
3729      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3730      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3731      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3741  int main(int argc, const char ** argv) {
3741      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3742      char * removeArgs = NULL;      char * removeArgs = NULL;
3743      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3744        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3745      const char * chptr = NULL;      const char * chptr = NULL;
3746      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3747      struct grubConfig * config;      struct grubConfig * config;
3748      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3749      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3750      int displayDefault = 0;      int displayDefault = 0;
3751        int displayDefaultIndex = 0;
3752        int displayDefaultTitle = 0;
3753        int defaultIndex = -1;
3754      struct poptOption options[] = {      struct poptOption options[] = {
3755   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3756      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2322  int main(int argc, const char ** argv) { Line 3768  int main(int argc, const char ** argv) {
3768   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3769      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3770      _("bootfs") },      _("bootfs") },
3771  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3772   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3773      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3774  #endif  #endif
3775   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3776      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 2335  int main(int argc, const char ** argv) { Line 3781  int main(int argc, const char ** argv) {
3781        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3782        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3783        "template"), NULL },        "template"), NULL },
3784     { "debug", 0, 0, &debug, 0,
3785        _("print debugging information for failures") },
3786   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3787      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3788     { "default-index", 0, 0, &displayDefaultIndex, 0,
3789        _("display the index of the default kernel") },
3790     { "default-title", 0, 0, &displayDefaultTitle, 0,
3791        _("display the title of the default kernel") },
3792   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3793      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3794     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3795        _("configure extlinux bootloader (from syslinux)") },
3796   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3797      _("configure grub bootloader") },      _("configure grub bootloader") },
3798     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3799        _("configure grub2 bootloader") },
3800   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3801      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3802      _("kernel-path") },      _("kernel-path") },
3803   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3804      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3805     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3806        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3807   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3808      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3809   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3823  int main(int argc, const char ** argv) {
3823   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3824      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3825        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3826     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3827        _("make the given entry index the default entry"),
3828        _("entry-index") },
3829   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3830      _("configure silo bootloader") },      _("configure silo bootloader") },
3831   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3843  int main(int argc, const char ** argv) {
3843   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3844      };      };
3845    
3846        useextlinuxmenu=0;
3847    
3848        signal(SIGSEGV, traceback);
3849    
3850      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3851      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3852    
# Line 2391  int main(int argc, const char ** argv) { Line 3856  int main(int argc, const char ** argv) {
3856      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3857      exit(0);      exit(0);
3858      break;      break;
3859      case 'i':
3860        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3861         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3862        } else {
3863     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3864     return 1;
3865        }
3866        break;
3867   }   }
3868      }      }
3869    
# Line 2406  int main(int argc, const char ** argv) { Line 3879  int main(int argc, const char ** argv) {
3879   return 1;   return 1;
3880      }      }
3881    
3882      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3883   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3884     configureExtLinux ) > 1) {
3885   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3886   return 1;   return 1;
3887      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3888   fprintf(stderr,   fprintf(stderr,
3889      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3890   return 1;   return 1;
3891        } else if (configureGrub2) {
3892     cfi = &grub2ConfigType;
3893      } else if (configureLilo) {      } else if (configureLilo) {
3894   cfi = &liloConfigType;   cfi = &liloConfigType;
3895      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3902  int main(int argc, const char ** argv) {
3902          cfi = &siloConfigType;          cfi = &siloConfigType;
3903      } else if (configureZipl) {      } else if (configureZipl) {
3904          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3905        } else if (configureExtLinux) {
3906     cfi = &extlinuxConfigType;
3907     useextlinuxmenu=1;
3908      }      }
3909    
3910      if (!cfi) {      if (!cfi) {
3911            if (grub2FindConfig(&grub2ConfigType))
3912        cfi = &grub2ConfigType;
3913     else
3914        #ifdef __ia64__        #ifdef __ia64__
3915   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3916        #elif __powerpc__        #elif __powerpc__
3917   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3918        #elif __sparc__        #elif __sparc__
3919          cfi = &siloConfigType;              cfi = &siloConfigType;
3920        #elif __s390__        #elif __s390__
3921          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3922        #elif __s390x__        #elif __s390x__
3923          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3924        #else        #else
3925   cfi = &grubConfigType;      cfi = &grubConfigType;
3926        #endif        #endif
3927      }      }
3928    
3929      if (!grubConfig)      if (!grubConfig) {
3930   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3931        grubConfig = cfi->findConfig(cfi);
3932     if (!grubConfig)
3933        grubConfig = cfi->defaultConfig;
3934        }
3935    
3936      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3937    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
3938    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
3939        (defaultIndex >= 0))) {
3940   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3941    "specified option"));    "specified option"));
3942   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3952  int main(int argc, const char ** argv) {
3952      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3953   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3954   return 1;   return 1;
3955      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3956    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3957    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3958   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3959   return 1;   return 1;
3960      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 3978  int main(int argc, const char ** argv) {
3978   makeDefault = 1;   makeDefault = 1;
3979   defaultKernel = NULL;   defaultKernel = NULL;
3980      }      }
3981        else if (defaultKernel && (defaultIndex >= 0)) {
3982     fprintf(stderr, _("grubby: --set-default and --set-default-index "
3983      "may not be used together\n"));
3984     return 1;
3985        }
3986    
3987      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3988   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3989   "is used\n"));   "is used\n"));
3990   return 1;   return 1;
3991      }      }
3992    
3993      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3994   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3995          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
3996     && (defaultIndex == -1)) {
3997   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3998   return 1;   return 1;
3999      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4013  int main(int argc, const char ** argv) {
4013   bootPrefix = "";   bootPrefix = "";
4014      }      }
4015    
4016        if (!cfi->mbAllowExtraInitRds &&
4017     extraInitrdCount > 0) {
4018     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4019     return 1;
4020        }
4021    
4022      if (bootloaderProbe) {      if (bootloaderProbe) {
4023   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4024   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4025    
4026     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4027     if (grub2config) {
4028        gconfig = readConfig(grub2config, &grub2ConfigType);
4029        if (!gconfig)
4030     gr2c = 1;
4031        else
4032     gr2c = checkForGrub2(gconfig);
4033     }
4034    
4035   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4036      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4037        gconfig = readConfig(grubconfig, &grubConfigType);
4038      if (!gconfig)      if (!gconfig)
4039   grc = 1;   grc = 1;
4040      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4049  int main(int argc, const char ** argv) {
4049   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4050   }   }
4051    
4052   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4053        econfig = readConfig(eliloConfigType.defaultConfig,
4054     &eliloConfigType);
4055        if (!econfig)
4056     erc = 1;
4057        else
4058     erc = checkForElilo(econfig);
4059     }
4060    
4061     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4062        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4063        if (!lconfig)
4064     extrc = 1;
4065        else
4066     extrc = checkForExtLinux(lconfig);
4067     }
4068    
4069    
4070     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4071        yconfig = readConfig(yabootConfigType.defaultConfig,
4072     &yabootConfigType);
4073        if (!yconfig)
4074     yrc = 1;
4075        else
4076     yrc = checkForYaboot(yconfig);
4077     }
4078    
4079     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4080     erc == 1)
4081        return 1;
4082    
4083   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4084     if (gr2c == 2) printf("grub2\n");
4085   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4086     if (extrc == 2) printf("extlinux\n");
4087     if (yrc == 2) printf("yaboot\n");
4088     if (erc == 2) printf("elilo\n");
4089    
4090   return 0;   return 0;
4091      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4103  int main(int argc, const char ** argv) {
4103   if (!entry) return 0;   if (!entry) return 0;
4104   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4105    
4106   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4107   if (!line) return 0;   if (!line) return 0;
4108    
4109          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4111  int main(int argc, const char ** argv) {
4111                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4112    
4113   return 0;   return 0;
4114    
4115        } else if (displayDefaultTitle) {
4116     struct singleLine * line;
4117     struct singleEntry * entry;
4118    
4119     if (config->defaultImage == -1) return 0;
4120     entry = findEntryByIndex(config, config->defaultImage);
4121     if (!entry) return 0;
4122    
4123     if (!configureGrub2) {
4124      line = getLineByType(LT_TITLE, entry->lines);
4125      if (!line) return 0;
4126      printf("%s\n", line->elements[1].item);
4127    
4128     } else {
4129      char * title;
4130    
4131      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4132      line = getLineByType(LT_MENUENTRY, entry->lines);
4133      if (!line) return 0;
4134      title = grub2ExtractTitle(line);
4135      if (title)
4136        printf("%s\n", title);
4137     }
4138     return 0;
4139    
4140        } else if (displayDefaultIndex) {
4141            if (config->defaultImage == -1) return 0;
4142            printf("%i\n", config->defaultImage);
4143    
4144      } else if (kernelInfo)      } else if (kernelInfo)
4145   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4146    
# Line 2581  int main(int argc, const char ** argv) { Line 4152  int main(int argc, const char ** argv) {
4152      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4153      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4154      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4155      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4156      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4157      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4158                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4159        if (updateKernelPath && newKernelInitrd) {
4160                if (updateInitrd(config, updateKernelPath, bootPrefix,
4161                                 newKernelInitrd)) return 1;
4162        }
4163      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4164                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4165                         (const char **)extraInitrds, extraInitrdCount,
4166                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4167            
4168    
# Line 2597  int main(int argc, const char ** argv) { Line 4173  int main(int argc, const char ** argv) {
4173      }      }
4174    
4175      if (!outputFile)      if (!outputFile)
4176   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4177    
4178      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4179  }  }

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