Magellan Linux

Diff of /tags/grubby-8_21/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 1934 by niro, Mon Oct 1 12:08:46 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      do {      do {
1318   buf = alloca(len + 1);   buf = alloca(len + 1);
1319   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1320   if (rc == len) len += 256;   if (rc == len) len += 256;
1321      } while (rc == len);      } while (rc == len);
1322            
# Line 843  static int writeConfig(struct grubConfig Line 1351  static int writeConfig(struct grubConfig
1351      }      }
1352    
1353      line = cfg->theLines;      line = cfg->theLines;
1354        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1355      while (line) {      while (line) {
1356   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1357     line->numElements == 3 &&
1358     !strcmp(line->elements[1].item, defaultKw->key)) {
1359        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1360        needs &= ~MAIN_DEFAULT;
1361     } else if (line->type == LT_DEFAULT) {
1362      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1363      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1364   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1426  static int numEntries(struct grubConfig
1426      return i;      return i;
1427  }  }
1428    
1429    static char *findDiskForRoot()
1430    {
1431        int fd;
1432        char buf[65536];
1433        char *devname;
1434        char *chptr;
1435        int rc;
1436    
1437        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1438            fprintf(stderr, "grubby: failed to open %s: %s\n",
1439                    _PATH_MOUNTED, strerror(errno));
1440            return NULL;
1441        }
1442    
1443        rc = read(fd, buf, sizeof(buf) - 1);
1444        if (rc <= 0) {
1445            fprintf(stderr, "grubby: failed to read %s: %s\n",
1446                    _PATH_MOUNTED, strerror(errno));
1447            close(fd);
1448            return NULL;
1449        }
1450        close(fd);
1451        buf[rc] = '\0';
1452        chptr = buf;
1453    
1454        char *foundanswer = NULL;
1455    
1456        while (chptr && chptr != buf+rc) {
1457            devname = chptr;
1458    
1459            /*
1460             * The first column of a mtab entry is the device, but if the entry is a
1461             * special device it won't start with /, so move on to the next line.
1462             */
1463            if (*devname != '/') {
1464                chptr = strchr(chptr, '\n');
1465                if (chptr)
1466                    chptr++;
1467                continue;
1468            }
1469    
1470            /* Seek to the next space */
1471            chptr = strchr(chptr, ' ');
1472            if (!chptr) {
1473                fprintf(stderr, "grubby: error parsing %s: %s\n",
1474                        _PATH_MOUNTED, strerror(errno));
1475                return NULL;
1476            }
1477    
1478            /*
1479             * The second column of a mtab entry is the mount point, we are looking
1480             * for '/' obviously.
1481             */
1482            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1483                /* remember the last / entry in mtab */
1484               foundanswer = devname;
1485            }
1486    
1487            /* Next line */
1488            chptr = strchr(chptr, '\n');
1489            if (chptr)
1490                chptr++;
1491        }
1492    
1493        /* Return the last / entry found */
1494        if (foundanswer) {
1495            chptr = strchr(foundanswer, ' ');
1496            *chptr = '\0';
1497            return strdup(foundanswer);
1498        }
1499    
1500        return NULL;
1501    }
1502    
1503    void printEntry(struct singleEntry * entry) {
1504        int i;
1505        struct singleLine * line;
1506    
1507        for (line = entry->lines; line; line = line->next) {
1508     fprintf(stderr, "DBG: %s", line->indent);
1509     for (i = 0; i < line->numElements; i++) {
1510        /* Need to handle this, because we strip the quotes from
1511         * menuentry when read it. */
1512        if (line->type == LT_MENUENTRY && i == 1) {
1513     if(!isquote(*line->elements[i].item))
1514        fprintf(stderr, "\'%s\'", line->elements[i].item);
1515     else
1516        fprintf(stderr, "%s", line->elements[i].item);
1517     fprintf(stderr, "%s", line->elements[i].indent);
1518    
1519     continue;
1520        }
1521        
1522        fprintf(stderr, "%s%s",
1523        line->elements[i].item, line->elements[i].indent);
1524     }
1525     fprintf(stderr, "\n");
1526        }
1527    }
1528    
1529    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1530    {
1531        va_list argp;
1532    
1533        if (!debug)
1534     return;
1535    
1536        va_start(argp, fmt);
1537        fprintf(stderr, "DBG: Image entry failed: ");
1538        vfprintf(stderr, fmt, argp);
1539        printEntry(entry);
1540        va_end(argp);
1541    }
1542    
1543    #define beginswith(s, c) ((s) && (s)[0] == (c))
1544    
1545    static int endswith(const char *s, char c)
1546    {
1547     int slen;
1548    
1549     if (!s || !s[0])
1550     return 0;
1551     slen = strlen(s) - 1;
1552    
1553     return s[slen] == c;
1554    }
1555    
1556  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1557    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1558      struct singleLine * line;      struct singleLine * line;
1559      char * fullName;      char * fullName;
1560      int i;      int i;
     struct stat sb, sb2;  
1561      char * dev;      char * dev;
     char * end;  
1562      char * rootspec;      char * rootspec;
1563        char * rootdev;
1564    
1565      line = entry->lines;      if (skipRemoved && entry->skip) {
1566      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1567         return 0;
1568      if (!line) return 0;      }
1569      if (skipRemoved && entry->skip) return 0;  
1570      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1571        if (!line) {
1572     notSuitablePrintf(entry, "no line found\n");
1573     return 0;
1574        }
1575        if (line->numElements < 2) {
1576     notSuitablePrintf(entry, "line has only %d elements\n",
1577        line->numElements);
1578     return 0;
1579        }
1580    
1581      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1582    
1583      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1584        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1585      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1586      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1587              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1588                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1589      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1590                line->elements[1].item + rootspec_offset);
1591        if (access(fullName, R_OK)) {
1592     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1593     return 0;
1594        }
1595      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1596   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1597      if (i < line->numElements) {      if (i < line->numElements) {
1598   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1599      } else {      } else {
1600   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1601   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1602    
1603   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1604      dev = line->elements[1].item;      dev = line->elements[1].item;
1605   } else {   } else {
1606              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1607      /* 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.
1608      line = entry->lines;       */
1609        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1610    
1611              /* failed to find one */              /* failed to find one */
1612              if (!line) return 0;              if (!line) {
1613     notSuitablePrintf(entry, "no line found\n");
1614     return 0;
1615                }
1616    
1617      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1618          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1619      if (i < line->numElements)      if (i < line->numElements)
1620          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1621      else {      else {
1622     notSuitablePrintf(entry, "no root= entry found\n");
1623   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1624          return 0;          return 0;
1625              }              }
1626   }   }
1627      }      }
1628    
1629      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1630   dev += 6;      if (!getpathbyspec(dev)) {
1631            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1632   /* check which device has this label */          return 0;
1633   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1634   if (!dev) return 0;   dev = getpathbyspec(dev);
1635    
1636        rootdev = findDiskForRoot();
1637        if (!rootdev) {
1638            notSuitablePrintf(entry, "can't find root device\n");
1639     return 0;
1640      }      }
1641    
1642      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1643   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1644      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1645      } else {          free(rootdev);
1646   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1647   if (*end) return 0;      }
1648    
1649        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1650            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1651     getuuidbydev(rootdev), getuuidbydev(dev));
1652     free(rootdev);
1653            return 0;
1654      }      }
     stat("/", &sb2);  
1655    
1656      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1657    
1658      return 1;      return 1;
1659  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1697  struct singleEntry * findEntryByPath(str
1697   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1698   if (!entry) return NULL;   if (!entry) return NULL;
1699    
1700   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1701   if (!line) return NULL;   if (!line) return NULL;
1702    
1703   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1735  struct singleEntry * findEntryByPath(str
1735    
1736   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1737      prefix = "";      prefix = "";
1738      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1739      kernel += 6;      kernel += 6;
1740   }   }
1741    
1742   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1743      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
   
1744    
1745      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;  
                 }  
             }  
1746    
1747      i++;      /* check all the lines matching checkType */
1748        for (line = entry->lines; line; line = line->next) {
1749     line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1750         LT_KERNEL|LT_MBMODULE|LT_HYPER :
1751         checkType, line);
1752     if (!line) break;  /* not found in this entry */
1753    
1754     if (line && line->type != LT_MENUENTRY &&
1755     line->numElements >= 2) {
1756        rootspec = getRootSpecifier(line->elements[1].item);
1757        if (!strcmp(line->elements[1].item +
1758     ((rootspec != NULL) ? strlen(rootspec) : 0),
1759     kernel + strlen(prefix)))
1760     break;
1761     }
1762     if(line->type == LT_MENUENTRY &&
1763     !strcmp(line->elements[1].item, kernel))
1764        break;
1765        }
1766    
1767        /* make sure this entry has a kernel identifier; this skips
1768         * non-Linux boot entries (could find netbsd etc, though, which is
1769         * unfortunate)
1770         */
1771        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1772     break; /* found 'im! */
1773   }   }
1774    
1775   if (index) *index = i;   if (index) *index = i;
1776      }      }
1777    
     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);  
     }  
   
1778      return entry;      return entry;
1779  }  }
1780    
# Line 1200  void markRemovedImage(struct grubConfig Line 1853  void markRemovedImage(struct grubConfig
1853        const char * prefix) {        const char * prefix) {
1854      struct singleEntry * entry;      struct singleEntry * entry;
1855    
1856      if (!image) return;      if (!image)
1857     return;
1858    
1859        /* check and see if we're removing the default image */
1860        if (isdigit(*image)) {
1861     entry = findEntryByPath(cfg, image, prefix, NULL);
1862     if(entry)
1863        entry->skip = 1;
1864     return;
1865        }
1866    
1867      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1868   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1870  void markRemovedImage(struct grubConfig
1870    
1871  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1872       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1873       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1874      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1875      int i, j;      int i, j;
1876    
1877      if (newIsDefault) {      if (newIsDefault) {
1878   config->defaultImage = 0;   config->defaultImage = 0;
1879   return;   return;
1880        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1881     if (findEntryByIndex(config, index))
1882        config->defaultImage = index;
1883     else
1884        config->defaultImage = -1;
1885     return;
1886      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1887   i = 0;   i = 0;
1888   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1895  void setDefaultImage(struct grubConfig *
1895    
1896      /* defaultImage now points to what we'd like to use, but before any order      /* defaultImage now points to what we'd like to use, but before any order
1897         changes */         changes */
1898      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1899     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1900        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1901        return;        return;
1902    
# Line 1286  void displayEntry(struct singleEntry * e Line 1955  void displayEntry(struct singleEntry * e
1955      char * root = NULL;      char * root = NULL;
1956      int i;      int i;
1957    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1958      printf("index=%d\n", index);      printf("index=%d\n", index);
1959    
1960      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1961        if (!line) {
1962            printf("non linux entry\n");
1963            return;
1964        }
1965    
1966        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
1967     printf("kernel=%s\n", line->elements[1].item);
1968        else
1969     printf("kernel=%s%s\n", prefix, line->elements[1].item);
1970    
1971      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1972   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1983  void displayEntry(struct singleEntry * e
1983   }   }
1984   printf("\"\n");   printf("\"\n");
1985      } else {      } else {
1986   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1987   if (line) {   if (line) {
1988      char * s;      char * s;
1989    
# Line 1334  void displayEntry(struct singleEntry * e Line 2007  void displayEntry(struct singleEntry * e
2007      }      }
2008    
2009      if (!root) {      if (!root) {
2010   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2011   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2012      root=line->elements[1].item;      root=line->elements[1].item;
2013      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2022  void displayEntry(struct singleEntry * e
2022   printf("root=%s\n", s);   printf("root=%s\n", s);
2023      }      }
2024    
2025      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2026    
2027      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2028   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2029        printf("initrd=");
2030     else
2031        printf("initrd=%s", prefix);
2032    
2033   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2034      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2035   printf("\n");   printf("\n");
2036      }      }
2037    
2038        line = getLineByType(LT_TITLE, entry->lines);
2039        if (line) {
2040     printf("title=%s\n", line->elements[1].item);
2041        } else {
2042     char * title;
2043     line = getLineByType(LT_MENUENTRY, entry->lines);
2044     title = grub2ExtractTitle(line);
2045     if (title)
2046        printf("title=%s\n", title);
2047        }
2048    }
2049    
2050    int isSuseSystem(void) {
2051        const char * path;
2052        const static char default_path[] = "/etc/SuSE-release";
2053    
2054        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2055     path = default_path;
2056    
2057        if (!access(path, R_OK))
2058     return 1;
2059        return 0;
2060    }
2061    
2062    int isSuseGrubConf(const char * path) {
2063        FILE * grubConf;
2064        char * line = NULL;
2065        size_t len = 0, res = 0;
2066    
2067        grubConf = fopen(path, "r");
2068        if (!grubConf) {
2069            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2070     return 0;
2071        }
2072    
2073        while ((res = getline(&line, &len, grubConf)) != -1) {
2074     if (!strncmp(line, "setup", 5)) {
2075        fclose(grubConf);
2076        free(line);
2077        return 1;
2078     }
2079        }
2080    
2081        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2082          path);
2083    
2084        fclose(grubConf);
2085        free(line);
2086        return 0;
2087    }
2088    
2089    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2090        FILE * grubConf;
2091        char * line = NULL;
2092        size_t res = 0, len = 0;
2093    
2094        if (!path) return 1;
2095        if (!lbaPtr) return 1;
2096    
2097        grubConf = fopen(path, "r");
2098        if (!grubConf) return 1;
2099    
2100        while ((res = getline(&line, &len, grubConf)) != -1) {
2101     if (line[res - 1] == '\n')
2102        line[res - 1] = '\0';
2103     else if (len > res)
2104        line[res] = '\0';
2105     else {
2106        line = realloc(line, res + 1);
2107        line[res] = '\0';
2108     }
2109    
2110     if (!strncmp(line, "setup", 5)) {
2111        if (strstr(line, "--force-lba")) {
2112            *lbaPtr = 1;
2113        } else {
2114            *lbaPtr = 0;
2115        }
2116        dbgPrintf("lba: %i\n", *lbaPtr);
2117        break;
2118     }
2119        }
2120    
2121        free(line);
2122        fclose(grubConf);
2123        return 0;
2124    }
2125    
2126    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2127        FILE * grubConf;
2128        char * line = NULL;
2129        size_t res = 0, len = 0;
2130        char * lastParamPtr = NULL;
2131        char * secLastParamPtr = NULL;
2132        char installDeviceNumber = '\0';
2133        char * bounds = NULL;
2134    
2135        if (!path) return 1;
2136        if (!devicePtr) return 1;
2137    
2138        grubConf = fopen(path, "r");
2139        if (!grubConf) return 1;
2140    
2141        while ((res = getline(&line, &len, grubConf)) != -1) {
2142     if (strncmp(line, "setup", 5))
2143        continue;
2144    
2145     if (line[res - 1] == '\n')
2146        line[res - 1] = '\0';
2147     else if (len > res)
2148        line[res] = '\0';
2149     else {
2150        line = realloc(line, res + 1);
2151        line[res] = '\0';
2152     }
2153    
2154     lastParamPtr = bounds = line + res;
2155    
2156     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2157     while (!isspace(*lastParamPtr))
2158        lastParamPtr--;
2159     lastParamPtr++;
2160    
2161     secLastParamPtr = lastParamPtr - 2;
2162     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2163    
2164     if (lastParamPtr + 3 > bounds) {
2165        dbgPrintf("lastParamPtr going over boundary");
2166        fclose(grubConf);
2167        free(line);
2168        return 1;
2169     }
2170     if (!strncmp(lastParamPtr, "(hd", 3))
2171        lastParamPtr += 3;
2172     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2173    
2174     /*
2175     * Second last parameter will decide wether last parameter is
2176     * an IMAGE_DEVICE or INSTALL_DEVICE
2177     */
2178     while (!isspace(*secLastParamPtr))
2179        secLastParamPtr--;
2180     secLastParamPtr++;
2181    
2182     if (secLastParamPtr + 3 > bounds) {
2183        dbgPrintf("secLastParamPtr going over boundary");
2184        fclose(grubConf);
2185        free(line);
2186        return 1;
2187     }
2188     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2189     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2190        secLastParamPtr += 3;
2191        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2192        installDeviceNumber = *secLastParamPtr;
2193     } else {
2194        installDeviceNumber = *lastParamPtr;
2195     }
2196    
2197     *devicePtr = malloc(6);
2198     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2199     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2200     fclose(grubConf);
2201     free(line);
2202     return 0;
2203        }
2204    
2205        free(line);
2206        fclose(grubConf);
2207        return 1;
2208    }
2209    
2210    int grubGetBootFromDeviceMap(const char * device,
2211         char ** bootPtr) {
2212        FILE * deviceMap;
2213        char * line = NULL;
2214        size_t res = 0, len = 0;
2215        char * devicePtr;
2216        char * bounds = NULL;
2217        const char * path;
2218        const static char default_path[] = "/boot/grub/device.map";
2219    
2220        if (!device) return 1;
2221        if (!bootPtr) return 1;
2222    
2223        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2224     path = default_path;
2225    
2226        dbgPrintf("opening grub device.map file from: %s\n", path);
2227        deviceMap = fopen(path, "r");
2228        if (!deviceMap)
2229     return 1;
2230    
2231        while ((res = getline(&line, &len, deviceMap)) != -1) {
2232            if (!strncmp(line, "#", 1))
2233        continue;
2234    
2235     if (line[res - 1] == '\n')
2236        line[res - 1] = '\0';
2237     else if (len > res)
2238        line[res] = '\0';
2239     else {
2240        line = realloc(line, res + 1);
2241        line[res] = '\0';
2242     }
2243    
2244     devicePtr = line;
2245     bounds = line + res;
2246    
2247     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2248        devicePtr++;
2249     dbgPrintf("device: %s\n", devicePtr);
2250    
2251     if (!strncmp(devicePtr, device, strlen(device))) {
2252        devicePtr += strlen(device);
2253        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2254            devicePtr++;
2255    
2256        *bootPtr = strdup(devicePtr);
2257        break;
2258     }
2259        }
2260    
2261        free(line);
2262        fclose(deviceMap);
2263        return 0;
2264    }
2265    
2266    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2267        char * grubDevice;
2268    
2269        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2270     dbgPrintf("error looking for grub installation device\n");
2271        else
2272     dbgPrintf("grubby installation device: %s\n", grubDevice);
2273    
2274        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2275     dbgPrintf("error looking for grub boot device\n");
2276        else
2277     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2278    
2279        free(grubDevice);
2280        return 0;
2281    }
2282    
2283    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2284        /*
2285         * This SuSE grub configuration file at this location is not your average
2286         * grub configuration file, but instead the grub commands used to setup
2287         * grub on that system.
2288         */
2289        const char * path;
2290        const static char default_path[] = "/etc/grub.conf";
2291    
2292        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2293     path = default_path;
2294    
2295        if (!isSuseGrubConf(path)) return 1;
2296    
2297        if (lbaPtr) {
2298            *lbaPtr = 0;
2299            if (suseGrubConfGetLba(path, lbaPtr))
2300                return 1;
2301        }
2302    
2303        if (bootPtr) {
2304            *bootPtr = NULL;
2305            suseGrubConfGetBoot(path, bootPtr);
2306        }
2307    
2308        return 0;
2309  }  }
2310    
2311  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2315  int parseSysconfigGrub(int * lbaPtr, cha
2315      char * start;      char * start;
2316      char * param;      char * param;
2317    
2318      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2319      if (!in) return 1;      if (!in) return 1;
2320    
2321      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2356  int parseSysconfigGrub(int * lbaPtr, cha
2356  }  }
2357    
2358  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2359      char * boot;      char * boot = NULL;
2360      int lba;      int lba;
2361    
2362      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2363   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2364   if (boot) printf("boot=%s\n", boot);      free(boot);
2365        return;
2366     }
2367        } else {
2368            if (parseSysconfigGrub(&lba, &boot)) {
2369        free(boot);
2370        return;
2371     }
2372        }
2373    
2374        if (lba) printf("lba\n");
2375        if (boot) {
2376     printf("boot=%s\n", boot);
2377     free(boot);
2378      }      }
2379  }  }
2380    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2390  int displayInfo(struct grubConfig * conf
2390   return 1;   return 1;
2391      }      }
2392    
2393      /* 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
2394         be a better way */         be a better way */
2395      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2396   dumpSysconfigGrub();   dumpSysconfigGrub();
2397      } else {      } else {
2398   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2399   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2400      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2401   }   }
2402    
2403   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2404   if (line) printf("lba\n");   if (line) printf("lba\n");
2405      }      }
2406    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2415  int displayInfo(struct grubConfig * conf
2415      return 0;      return 0;
2416  }  }
2417    
2418    struct singleLine * addLineTmpl(struct singleEntry * entry,
2419     struct singleLine * tmplLine,
2420     struct singleLine * prevLine,
2421     const char * val,
2422     struct configFileInfo * cfi)
2423    {
2424        struct singleLine * newLine = lineDup(tmplLine);
2425    
2426        if (val) {
2427     /* override the inherited value with our own.
2428     * This is a little weak because it only applies to elements[1]
2429     */
2430     if (newLine->numElements > 1)
2431        removeElement(newLine, 1);
2432     insertElement(newLine, val, 1, cfi);
2433    
2434     /* but try to keep the rootspec from the template... sigh */
2435     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2436        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2437        if (rootspec != NULL) {
2438     free(newLine->elements[1].item);
2439     newLine->elements[1].item =
2440        sdupprintf("%s%s", rootspec, val);
2441        }
2442     }
2443        }
2444    
2445        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2446          newLine->elements[0].item : "");
2447    
2448        if (!entry->lines) {
2449     /* first one on the list */
2450     entry->lines = newLine;
2451        } else if (prevLine) {
2452     /* add after prevLine */
2453     newLine->next = prevLine->next;
2454     prevLine->next = newLine;
2455        }
2456    
2457        return newLine;
2458    }
2459    
2460  /* val may be NULL */  /* val may be NULL */
2461  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2462       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2463       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2464       char * val) {       const char * val) {
2465      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2466      int i;      struct keywordTypes * kw;
2467        struct singleLine tmpl;
2468    
2469      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2470   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2471      if (type != LT_TITLE || !cfi->titleBracketed)       */
2472          if (!cfi->keywords[i].key) abort();  
2473        if (type == LT_TITLE && cfi->titleBracketed) {
2474     /* we're doing a bracketed title (zipl) */
2475     tmpl.type = type;
2476     tmpl.numElements = 1;
2477     tmpl.elements = alloca(sizeof(*tmpl.elements));
2478     tmpl.elements[0].item = alloca(strlen(val)+3);
2479     sprintf(tmpl.elements[0].item, "[%s]", val);
2480     tmpl.elements[0].indent = "";
2481     val = NULL;
2482        } else if (type == LT_MENUENTRY) {
2483     char *lineend = "--class gnu-linux --class gnu --class os {";
2484     if (!val) {
2485        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2486        abort();
2487     }
2488     kw = getKeywordByType(type, cfi);
2489     if (!kw) {
2490        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2491        abort();
2492     }
2493     tmpl.indent = "";
2494     tmpl.type = type;
2495     tmpl.numElements = 3;
2496     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2497     tmpl.elements[0].item = kw->key;
2498     tmpl.elements[0].indent = alloca(2);
2499     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2500     tmpl.elements[1].item = (char *)val;
2501     tmpl.elements[1].indent = alloca(2);
2502     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2503     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2504     strcpy(tmpl.elements[2].item, lineend);
2505     tmpl.elements[2].indent = "";
2506        } else {
2507     kw = getKeywordByType(type, cfi);
2508     if (!kw) {
2509        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2510        abort();
2511     }
2512     tmpl.type = type;
2513     tmpl.numElements = val ? 2 : 1;
2514     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2515     tmpl.elements[0].item = kw->key;
2516     tmpl.elements[0].indent = alloca(2);
2517     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2518     if (val) {
2519        tmpl.elements[1].item = (char *)val;
2520        tmpl.elements[1].indent = "";
2521     }
2522        }
2523    
2524      /* 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
2525         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2526         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
2527         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2528         differently from the rest) */         differently from the rest) */
2529      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2530   line = entry->lines;   if (line->numElements) prev = line;
2531   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2532   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;  
2533      }      }
2534    
2535      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2536          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2537          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2538          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2539          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2540          line->elements[0].indent = malloc(2);   else
2541          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2542          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2543             if (menuEntry)
2544          if (val) {      tmpl.indent = "\t";
2545              line->elements[1].item = val;   else if (prev == entry->lines)
2546              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2547          }   else
2548      } 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("");  
2549      }      }
2550    
2551      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2552  }  }
2553    
2554  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2573  void removeLine(struct singleEntry * ent
2573      free(line);      free(line);
2574  }  }
2575    
2576    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2577    {
2578        struct singleLine newLine = {
2579     .indent = tmplLine->indent,
2580     .type = tmplLine->type,
2581     .next = tmplLine->next,
2582        };
2583        int firstQuotedItem = -1;
2584        int quoteLen = 0;
2585        int j;
2586        int element = 0;
2587        char *c;
2588    
2589        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2590        strcpy(c, tmplLine->elements[0].item);
2591        insertElement(&newLine, c, element++, cfi);
2592        free(c);
2593        c = NULL;
2594    
2595        for (j = 1; j < tmplLine->numElements; j++) {
2596     if (firstQuotedItem == -1) {
2597        quoteLen += strlen(tmplLine->elements[j].item);
2598        
2599        if (isquote(tmplLine->elements[j].item[0])) {
2600     firstQuotedItem = j;
2601            quoteLen += strlen(tmplLine->elements[j].indent);
2602        } else {
2603     c = malloc(quoteLen + 1);
2604     strcpy(c, tmplLine->elements[j].item);
2605     insertElement(&newLine, c, element++, cfi);
2606     free(c);
2607     quoteLen = 0;
2608        }
2609     } else {
2610        int itemlen = strlen(tmplLine->elements[j].item);
2611        quoteLen += itemlen;
2612        quoteLen += strlen(tmplLine->elements[j].indent);
2613        
2614        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2615     c = malloc(quoteLen + 1);
2616     c[0] = '\0';
2617     for (int i = firstQuotedItem; i < j+1; i++) {
2618        strcat(c, tmplLine->elements[i].item);
2619        strcat(c, tmplLine->elements[i].indent);
2620     }
2621     insertElement(&newLine, c, element++, cfi);
2622     free(c);
2623    
2624     firstQuotedItem = -1;
2625     quoteLen = 0;
2626        }
2627     }
2628        }
2629        while (tmplLine->numElements)
2630     removeElement(tmplLine, 0);
2631        if (tmplLine->elements)
2632     free(tmplLine->elements);
2633    
2634        tmplLine->numElements = newLine.numElements;
2635        tmplLine->elements = newLine.elements;
2636    }
2637    
2638    static void insertElement(struct singleLine * line,
2639      const char * item, int insertHere,
2640      struct configFileInfo * cfi)
2641    {
2642        struct keywordTypes * kw;
2643        char indent[2] = "";
2644    
2645        /* sanity check */
2646        if (insertHere > line->numElements) {
2647     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2648      insertHere, line->numElements);
2649     insertHere = line->numElements;
2650        }
2651    
2652        line->elements = realloc(line->elements, (line->numElements + 1) *
2653         sizeof(*line->elements));
2654        memmove(&line->elements[insertHere+1],
2655        &line->elements[insertHere],
2656        (line->numElements - insertHere) *
2657        sizeof(*line->elements));
2658        line->elements[insertHere].item = strdup(item);
2659    
2660        kw = getKeywordByType(line->type, cfi);
2661    
2662        if (line->numElements == 0) {
2663     indent[0] = '\0';
2664        } else if (insertHere == 0) {
2665     indent[0] = kw->nextChar;
2666        } else if (kw->separatorChar != '\0') {
2667     indent[0] = kw->separatorChar;
2668        } else {
2669     indent[0] = ' ';
2670        }
2671    
2672        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2673     /* move the end-of-line forward */
2674     line->elements[insertHere].indent =
2675        line->elements[insertHere-1].indent;
2676     line->elements[insertHere-1].indent = strdup(indent);
2677        } else {
2678     line->elements[insertHere].indent = strdup(indent);
2679        }
2680    
2681        line->numElements++;
2682    
2683        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2684          line->elements[0].item,
2685          line->elements[insertHere].item,
2686          line->elements[insertHere].indent,
2687          insertHere);
2688    }
2689    
2690    static void removeElement(struct singleLine * line, int removeHere) {
2691        int i;
2692    
2693        /* sanity check */
2694        if (removeHere >= line->numElements) return;
2695    
2696        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2697          removeHere, line->elements[removeHere].item);
2698    
2699        free(line->elements[removeHere].item);
2700    
2701        if (removeHere > 1) {
2702     /* previous argument gets this argument's post-indentation */
2703     free(line->elements[removeHere-1].indent);
2704     line->elements[removeHere-1].indent =
2705        line->elements[removeHere].indent;
2706        } else {
2707     free(line->elements[removeHere].indent);
2708        }
2709    
2710        /* now collapse the array, but don't bother to realloc smaller */
2711        for (i = removeHere; i < line->numElements - 1; i++)
2712     line->elements[i] = line->elements[i + 1];
2713    
2714        line->numElements--;
2715    }
2716    
2717  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2718      char * first, * second;      char * first, * second;
2719      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2736  int updateActualImage(struct grubConfig
2736      struct singleEntry * entry;      struct singleEntry * entry;
2737      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2738      int index = 0;      int index = 0;
2739      int i, j, k;      int i, k;
2740      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2741      const char ** arg;      const char ** arg;
2742      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2743      int firstElement;      int firstElement;
2744      int *usedElements, *usedArgs;      int *usedElements;
2745        int doreplace;
2746    
2747      if (!image) return 0;      if (!image) return 0;
2748    
# Line 1609  int updateActualImage(struct grubConfig Line 2769  int updateActualImage(struct grubConfig
2769   }   }
2770      }      }
2771    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2772    
2773      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2774   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2775    
2776      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2777   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2778    
2779      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2780    
2781      k = 0;   if (multibootArgs && !entry->multiboot)
2782      for (arg = newArgs; *arg; arg++)      continue;
2783          k++;  
2784      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2785     * LT_KERNELARGS, use that.  Otherwise use
2786     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2787     */
2788     if (useKernelArgs) {
2789        line = getLineByType(LT_KERNELARGS, entry->lines);
2790        if (!line) {
2791     /* no LT_KERNELARGS, need to add it */
2792     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2793           cfg->secondaryIndent, NULL);
2794        }
2795        firstElement = 1;
2796    
2797      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2798   index++;      line = getLineByType(LT_HYPER, entry->lines);
2799        if (!line) {
2800     /* a multiboot entry without LT_HYPER? */
2801     continue;
2802        }
2803        firstElement = 2;
2804    
2805   line = entry->lines;   } else {
2806   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2807   if (!line) continue;      if (!line) {
2808   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2809     continue;
2810          if (entry->multiboot && !multibootArgs) {      }
2811              /* 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;  
2812   }   }
2813    
2814   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2815      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2816      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2817     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2818        /* this is a multiboot entry, make sure there's
2819         * -- on the args line
2820         */
2821        for (i = firstElement; i < line->numElements; i++) {
2822     if (!strcmp(line->elements[i].item, "--"))
2823        break;
2824        }
2825        if (i == line->numElements) {
2826     /* assume all existing args are kernel args,
2827     * prepend -- to make it official
2828     */
2829     insertElement(line, "--", firstElement, cfg->cfi);
2830     i = firstElement;
2831        }
2832        if (!multibootArgs) {
2833     /* kernel args start after the -- */
2834     firstElement = i + 1;
2835        }
2836     } else if (cfg->cfi->mbConcatArgs) {
2837        /* this is a non-multiboot entry, remove hyper args */
2838        for (i = firstElement; i < line->numElements; i++) {
2839     if (!strcmp(line->elements[i].item, "--"))
2840        break;
2841        }
2842        if (i < line->numElements) {
2843     /* remove args up to -- */
2844     while (strcmp(line->elements[firstElement].item, "--"))
2845        removeElement(line, firstElement);
2846     /* remove -- */
2847     removeElement(line, firstElement);
2848        }
2849   }   }
2850    
2851          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2852    
2853          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2854   for (arg = newArgs; *arg; arg++) {  
2855              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2856      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2857     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2858        !strcmp(line->elements[i].item, "--"))
2859     {
2860        /* reached the end of hyper args, insert here */
2861        doreplace = 0;
2862        break;  
2863     }
2864                  if (usedElements[i])                  if (usedElements[i])
2865                      continue;                      continue;
2866   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2867                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2868      break;      break;
2869                  }                  }
2870              }              }
     chptr = strchr(*arg, '=');  
2871    
2872      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2873   /* replace */   /* direct replacement */
2874   free(line->elements[i].item);   free(line->elements[i].item);
2875   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("");  
  }  
2876    
2877   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2878   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2879      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2880   /* append */   if (rootLine) {
2881   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2882   (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(" ");  
2883   } else {   } else {
2884      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2885         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2886   }   }
2887        }
2888    
2889   line->numElements++;      else {
2890     /* insert/append */
2891     insertElement(line, *arg, i, cfg->cfi);
2892     usedElements = realloc(usedElements, line->numElements *
2893           sizeof(*usedElements));
2894     memmove(&usedElements[i + 1], &usedElements[i],
2895     line->numElements - i - 1);
2896     usedElements[i] = 1;
2897    
2898   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2899     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2900     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2901   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2902      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2903      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2904   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2905   }   }
2906      }      }
             k++;  
2907   }   }
2908    
2909          free(usedElements);          free(usedElements);
2910    
  /* 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? */  
2911   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2912      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2913   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2914        !strcmp(line->elements[i].item, "--"))
2915        /* reached the end of hyper args, stop here */
2916        break;
2917     if (!argMatch(line->elements[i].item, *arg)) {
2918        removeElement(line, i);
2919      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;  
2920   }   }
2921        }
2922   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2923        if (useRoot && !strncmp(*arg, "root=", 5)) {
2924   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2925      line->elements[j - 1] = line->elements[j];   if (rootLine)
2926        removeLine(entry, rootLine);
  line->numElements--;  
2927      }      }
2928   }   }
2929    
# Line 1760  int updateActualImage(struct grubConfig Line 2934  int updateActualImage(struct grubConfig
2934   }   }
2935      }      }
2936    
     free(usedArgs);  
2937      free(newArgs);      free(newArgs);
2938      free(oldArgs);      free(oldArgs);
2939    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2959  int updateImage(struct grubConfig * cfg,
2959      return rc;      return rc;
2960  }  }
2961    
2962    int updateInitrd(struct grubConfig * cfg, const char * image,
2963                     const char * prefix, const char * initrd) {
2964        struct singleEntry * entry;
2965        struct singleLine * line, * kernelLine, *endLine = NULL;
2966        int index = 0;
2967    
2968        if (!image) return 0;
2969    
2970        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2971            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2972            if (!kernelLine) continue;
2973    
2974            line = getLineByType(LT_INITRD, entry->lines);
2975            if (line)
2976                removeLine(entry, line);
2977            if (prefix) {
2978                int prefixLen = strlen(prefix);
2979                if (!strncmp(initrd, prefix, prefixLen))
2980                    initrd += prefixLen;
2981            }
2982     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2983     if (endLine)
2984        removeLine(entry, endLine);
2985            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2986            if (!line)
2987        return 1;
2988     if (endLine) {
2989        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2990                if (!line)
2991     return 1;
2992     }
2993    
2994            break;
2995        }
2996    
2997        return 0;
2998    }
2999    
3000  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3001      int fd;      int fd;
3002      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3020  int checkDeviceBootloader(const char * d
3020      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3021   return 0;   return 0;
3022    
3023      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3024   offset = boot[2] + 2;   offset = boot[2] + 2;
3025      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3026   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3027      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3028   offset = boot[1] + 2;        offset = boot[1] + 2;
3029            /*
3030     * it looks like grub, when copying stage1 into the mbr, patches stage1
3031     * right after the JMP location, replacing other instructions such as
3032     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3033     * different bytes.
3034     */
3035          if ((bootSect[offset + 1] == NOOP_OPCODE)
3036      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3037     offset = offset + 3;
3038          }
3039      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3040   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3041      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3177  int checkForLilo(struct grubConfig * con
3177      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3178  }  }
3179    
3180    int checkForGrub2(struct grubConfig * config) {
3181        if (!access("/etc/grub.d/", R_OK))
3182     return 2;
3183    
3184        return 1;
3185    }
3186    
3187  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3188      int fd;      int fd;
3189      unsigned char bootSect[512];      unsigned char bootSect[512];
3190      char * boot;      char * boot;
3191        int onSuse = isSuseSystem();
3192    
3193      if (parseSysconfigGrub(NULL, &boot))  
3194   return 0;      if (onSuse) {
3195     if (parseSuseGrubConf(NULL, &boot))
3196        return 0;
3197        } else {
3198     if (parseSysconfigGrub(NULL, &boot))
3199        return 0;
3200        }
3201    
3202      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3203      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3211  int checkForGrub(struct grubConfig * con
3211      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3212   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3213   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3214     close(fd);
3215   return 1;   return 1;
3216      }      }
3217      close(fd);      close(fd);
3218    
3219        /* The more elaborate checks do not work on SuSE. The checks done
3220         * seem to be reasonble (at least for now), so just return success
3221         */
3222        if (onSuse)
3223     return 2;
3224    
3225      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3226  }  }
3227    
3228    int checkForExtLinux(struct grubConfig * config) {
3229        int fd;
3230        unsigned char bootSect[512];
3231        char * boot;
3232        char executable[] = "/boot/extlinux/extlinux";
3233    
3234        printf("entered: checkForExtLinux()\n");
3235    
3236        if (parseSysconfigGrub(NULL, &boot))
3237     return 0;
3238    
3239        /* assume grub is not installed -- not an error condition */
3240        if (!boot)
3241     return 0;
3242    
3243        fd = open(executable, O_RDONLY);
3244        if (fd < 0)
3245     /* this doesn't exist if grub hasn't been installed */
3246     return 0;
3247    
3248        if (read(fd, bootSect, 512) != 512) {
3249     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3250     executable, strerror(errno));
3251     return 1;
3252        }
3253        close(fd);
3254    
3255        return checkDeviceBootloader(boot, bootSect);
3256    }
3257    
3258    int checkForYaboot(struct grubConfig * config) {
3259        /*
3260         * This is a simplistic check that we consider good enough for own puporses
3261         *
3262         * If we were to properly check if yaboot is *installed* we'd need to:
3263         * 1) get the system boot device (LT_BOOT)
3264         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3265         *    the content on the boot device
3266         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3267         * 4) check again if binary and boot device contents match
3268         */
3269        if (!access("/etc/yaboot.conf", R_OK))
3270     return 2;
3271    
3272        return 1;
3273    }
3274    
3275    int checkForElilo(struct grubConfig * config) {
3276        if (!access("/etc/elilo.conf", R_OK))
3277     return 2;
3278    
3279        return 1;
3280    }
3281    
3282  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3283      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3284    
# Line 1994  static char * getRootSpecifier(char * st Line 3290  static char * getRootSpecifier(char * st
3290      return rootspec;      return rootspec;
3291  }  }
3292    
3293    static char * getInitrdVal(struct grubConfig * config,
3294       const char * prefix, struct singleLine *tmplLine,
3295       const char * newKernelInitrd,
3296       const char ** extraInitrds, int extraInitrdCount)
3297    {
3298        char *initrdVal, *end;
3299        int i;
3300        size_t totalSize;
3301        size_t prefixLen;
3302        char separatorChar;
3303    
3304        prefixLen = strlen(prefix);
3305        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3306    
3307        for (i = 0; i < extraInitrdCount; i++) {
3308     totalSize += sizeof(separatorChar);
3309     totalSize += strlen(extraInitrds[i]) - prefixLen;
3310        }
3311    
3312        initrdVal = end = malloc(totalSize);
3313    
3314        end = stpcpy (end, newKernelInitrd + prefixLen);
3315    
3316        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3317        for (i = 0; i < extraInitrdCount; i++) {
3318     const char *extraInitrd;
3319     int j;
3320    
3321     extraInitrd = extraInitrds[i] + prefixLen;
3322     /* Don't add entries that are already there */
3323     if (tmplLine != NULL) {
3324        for (j = 2; j < tmplLine->numElements; j++)
3325     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3326        break;
3327    
3328        if (j != tmplLine->numElements)
3329     continue;
3330     }
3331    
3332     *end++ = separatorChar;
3333     end = stpcpy(end, extraInitrd);
3334        }
3335    
3336        return initrdVal;
3337    }
3338    
3339  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3340           const char * prefix,           const char * prefix,
3341   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3342   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3343                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3344                     const char * newMBKernel, const char * newMBKernelArgs) {
3345      struct singleEntry * new;      struct singleEntry * new;
3346      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3347      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3348      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3349    
3350      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3351    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3375  int addNewKernel(struct grubConfig * con
3375      config->entries = new;      config->entries = new;
3376    
3377      /* copy/update from the template */      /* copy/update from the template */
3378      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3379        if (newKernelInitrd)
3380     needs |= NEED_INITRD;
3381      if (newMBKernel) {      if (newMBKernel) {
3382          needs |= KERNEL_MB;          needs |= NEED_MB;
3383          new->multiboot = 1;          new->multiboot = 1;
3384      }      }
3385    
3386      if (template) {      if (template) {
3387   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3388      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3389      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3390   indent = tmplLine->indent;   {
3391        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3392    
3393      /* skip comments */      /* skip comments */
3394      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3395      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3396      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3397    
3398      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3399      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3400     if (!template->multiboot && (needs & NEED_MB)) {
3401              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3402                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3403                  struct singleLine *l;       * hypervisor at the same time.
3404                  needs &= ~ KERNEL_MB;       */
3405        if (config->cfi->mbHyperFirst) {
3406                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3407                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3408                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3409                      newMBKernel + strlen(prefix));
3410                  tmplLine = lastLine;   /* set up for adding the kernel line */
3411                  if (!new->lines) {   free(tmplLine->indent);
3412                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3413                  } else {   needs &= ~NEED_MB;
3414                      newLine->next = l;      }
3415                      newLine = l;      if (needs & NEED_KERNEL) {
3416                  }   /* use addLineTmpl to preserve line elements,
3417                  continue;   * otherwise we could just call addLine.  Unfortunately
3418              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3419                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3420                  continue; /* don't need multiboot kernel here */   * change below.
3421              }   */
3422     struct keywordTypes * mbm_kw =
3423        getKeywordByType(LT_MBMODULE, config->cfi);
3424     if (mbm_kw) {
3425        tmplLine->type = LT_MBMODULE;
3426        free(tmplLine->elements[0].item);
3427        tmplLine->elements[0].item = strdup(mbm_kw->key);
3428     }
3429     newLine = addLineTmpl(new, tmplLine, newLine,
3430          newKernelPath + strlen(prefix), config->cfi);
3431     needs &= ~NEED_KERNEL;
3432        }
3433        if (needs & NEED_MB) { /* !mbHyperFirst */
3434     newLine = addLine(new, config->cfi, LT_HYPER,
3435      config->secondaryIndent,
3436      newMBKernel + strlen(prefix));
3437     needs &= ~NEED_MB;
3438        }
3439     } else if (needs & NEED_KERNEL) {
3440        newLine = addLineTmpl(new, tmplLine, newLine,
3441      newKernelPath + strlen(prefix), config->cfi);
3442        needs &= ~NEED_KERNEL;
3443     }
3444    
3445      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3446   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3447   new->lines = newLine;   if (needs & NEED_MB) {
3448      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3449   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3450   newLine = newLine->next;      needs &= ~NEED_MB;
3451      }   }
3452    
3453        } else if (tmplLine->type == LT_MBMODULE &&
3454           tmplLine->numElements >= 2) {
3455     if (new->multiboot) {
3456        if (needs & NEED_KERNEL) {
3457     newLine = addLineTmpl(new, tmplLine, newLine,
3458          newKernelPath +
3459          strlen(prefix), config->cfi);
3460     needs &= ~NEED_KERNEL;
3461        } else if (config->cfi->mbInitRdIsModule &&
3462           (needs & NEED_INITRD)) {
3463     char *initrdVal;
3464     initrdVal = getInitrdVal(config, prefix, tmplLine,
3465     newKernelInitrd, extraInitrds,
3466     extraInitrdCount);
3467     newLine = addLineTmpl(new, tmplLine, newLine,
3468          initrdVal, config->cfi);
3469     free(initrdVal);
3470     needs &= ~NEED_INITRD;
3471        }
3472     } else if (needs & NEED_KERNEL) {
3473        /* template is multi but new is not,
3474         * insert the kernel in the first module slot
3475         */
3476        tmplLine->type = LT_KERNEL;
3477        free(tmplLine->elements[0].item);
3478        tmplLine->elements[0].item =
3479     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3480        newLine = addLineTmpl(new, tmplLine, newLine,
3481      newKernelPath + strlen(prefix), config->cfi);
3482        needs &= ~NEED_KERNEL;
3483     } else if (needs & NEED_INITRD) {
3484        char *initrdVal;
3485        /* template is multi but new is not,
3486         * insert the initrd in the second module slot
3487         */
3488        tmplLine->type = LT_INITRD;
3489        free(tmplLine->elements[0].item);
3490        tmplLine->elements[0].item =
3491     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3492        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3493        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3494        free(initrdVal);
3495        needs &= ~NEED_INITRD;
3496     }
3497    
     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));  
                 }  
3498      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3499      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3500   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3501   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3502                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3503                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3504                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3505                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3506                  }       */
3507                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3508                  if (rootspec != NULL) {   char *initrdVal;
3509                      newLine->elements[1].item = sdupprintf("%s%s",  
3510                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3511                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3512                                                             strlen(prefix));    config->secondaryIndent,
3513                  } else {    initrdVal);
3514                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3515                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3516                  }      }
3517              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3518                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3519   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3520                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3521                      free(newLine->elements[0].item);      free(initrdVal);
3522                      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);  
3523   }   }
3524    
3525   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3526   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3527   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3528     char *nkt = malloc(strlen(newKernelTitle)+3);
3529     strcpy(nkt, "'");
3530     strcat(nkt, newKernelTitle);
3531     strcat(nkt, "'");
3532     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3533     free(nkt);
3534     needs &= ~NEED_TITLE;
3535      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3536                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3537                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3538                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3539                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3540                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3541                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3542                                             newLine->numElements);     config->cfi->titleBracketed) {
3543        /* addLineTmpl doesn't handle titleBracketed */
3544                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3545                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3546                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3547                  newLine->numElements = 1;   }
3548              }      } else if (tmplLine->type == LT_ECHO) {
3549        requote(tmplLine, config->cfi);
3550        static const char *prefix = "'Loading ";
3551        if (tmplLine->numElements > 1 &&
3552        strstr(tmplLine->elements[1].item, prefix) &&
3553        masterLine->next && masterLine->next->type == LT_KERNEL) {
3554     char *newTitle = malloc(strlen(prefix) +
3555     strlen(newKernelTitle) + 2);
3556    
3557     strcpy(newTitle, prefix);
3558     strcat(newTitle, newKernelTitle);
3559     strcat(newTitle, "'");
3560     newLine = addLine(new, config->cfi, LT_ECHO,
3561     tmplLine->indent, newTitle);
3562     free(newTitle);
3563        } else {
3564     /* pass through other lines from the template */
3565     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3566     config->cfi);
3567        }
3568        } else {
3569     /* pass through other lines from the template */
3570     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3571        }
3572   }   }
3573    
3574      } else {      } else {
3575   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3576      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3577     */
3578     switch (config->cfi->entryStart) {
3579        case LT_KERNEL:
3580     if (new->multiboot && config->cfi->mbHyperFirst) {
3581        /* fall through to LT_HYPER */
3582     } else {
3583        newLine = addLine(new, config->cfi, LT_KERNEL,
3584          config->primaryIndent,
3585          newKernelPath + strlen(prefix));
3586        needs &= ~NEED_KERNEL;
3587        break;
3588     }
3589    
3590        case LT_HYPER:
3591     newLine = addLine(new, config->cfi, LT_HYPER,
3592      config->primaryIndent,
3593      newMBKernel + strlen(prefix));
3594     needs &= ~NEED_MB;
3595   break;   break;
         }  
3596    
3597   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3598      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3599       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3600       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3601      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3602       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3603      default:        config->primaryIndent, nkt);
3604                  /* zipl strikes again */   free(nkt);
3605                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3606                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3607                      chptr = newKernelTitle;   break;
3608                      type = LT_TITLE;      }
3609                      break;      case LT_TITLE:
3610                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3611                      abort();   char * templabel;
3612                  }   int x = 0, y = 0;
3613   }  
3614     templabel = strdup(newKernelTitle);
3615     while( templabel[x]){
3616     if( templabel[x] == ' ' ){
3617     y = x;
3618     while( templabel[y] ){
3619     templabel[y] = templabel[y+1];
3620     y++;
3621     }
3622     }
3623     x++;
3624     }
3625     newLine = addLine(new, config->cfi, LT_TITLE,
3626      config->primaryIndent, templabel);
3627     free(templabel);
3628     }else{
3629     newLine = addLine(new, config->cfi, LT_TITLE,
3630      config->primaryIndent, newKernelTitle);
3631     }
3632     needs &= ~NEED_TITLE;
3633     break;
3634    
3635   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3636   new->lines = newLine;   abort();
3637     }
3638      }      }
3639    
3640      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3641          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3642              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3643                                config->secondaryIndent,       */
3644                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3645          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3646              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3647                                config->secondaryIndent,    newKernelTitle);
3648                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3649          /* don't need to check for title as it's guaranteed to have been      }
3650           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3651           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3652          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3653              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3654                                config->secondaryIndent,   needs &= ~NEED_MB;
3655                                newKernelInitrd + strlen(prefix));      }
3656      } else {      if (needs & NEED_KERNEL) {
3657          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3658              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3659                                config->secondaryIndent,        config->cfi)) ?
3660                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3661          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3662              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3663                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3664                                newKernelTitle);      }
3665          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3666              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3667                                config->secondaryIndent,    config->secondaryIndent,
3668                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3669     needs &= ~NEED_MB;
3670        }
3671        if (needs & NEED_INITRD) {
3672     char *initrdVal;
3673     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3674     newLine = addLine(new, config->cfi,
3675      (new->multiboot && getKeywordByType(LT_MBMODULE,
3676          config->cfi)) ?
3677      LT_MBMODULE : LT_INITRD,
3678      config->secondaryIndent,
3679      initrdVal);
3680     free(initrdVal);
3681     needs &= ~NEED_INITRD;
3682        }
3683        if (needs & NEED_END) {
3684     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3685     config->secondaryIndent, NULL);
3686     needs &= ~NEED_END;
3687        }
3688    
3689        if (needs) {
3690     printf(_("grubby: needs=%d, aborting\n"), needs);
3691     abort();
3692      }      }
3693    
3694      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3697  int addNewKernel(struct grubConfig * con
3697      return 0;      return 0;
3698  }  }
3699    
3700    static void traceback(int signum)
3701    {
3702        void *array[40];
3703        size_t size;
3704    
3705        signal(SIGSEGV, SIG_DFL);
3706        memset(array, '\0', sizeof (array));
3707        size = backtrace(array, 40);
3708    
3709        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3710                (unsigned long)size);
3711        backtrace_symbols_fd(array, size, STDERR_FILENO);
3712        exit(1);
3713    }
3714    
3715  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3716      poptContext optCon;      poptContext optCon;
3717      char * grubConfig = NULL;      const char * grubConfig = NULL;
3718      char * outputFile = NULL;      char * outputFile = NULL;
3719      int arg = 0;      int arg = 0;
3720      int flags = 0;      int flags = 0;
3721      int badImageOkay = 0;      int badImageOkay = 0;
3722        int configureGrub2 = 0;
3723      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3724      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3725        int configureExtLinux = 0;
3726      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3727        int extraInitrdCount = 0;
3728      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3729      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3730      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3740  int main(int argc, const char ** argv) {
3740      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3741      char * removeArgs = NULL;      char * removeArgs = NULL;
3742      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3743        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3744      const char * chptr = NULL;      const char * chptr = NULL;
3745      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3746      struct grubConfig * config;      struct grubConfig * config;
3747      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3748      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3749      int displayDefault = 0;      int displayDefault = 0;
3750        int displayDefaultIndex = 0;
3751        int displayDefaultTitle = 0;
3752        int defaultIndex = -1;
3753      struct poptOption options[] = {      struct poptOption options[] = {
3754   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3755      _("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 3767  int main(int argc, const char ** argv) {
3767   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3768      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3769      _("bootfs") },      _("bootfs") },
3770  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3771   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3772      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3773  #endif  #endif
3774   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3775      _("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 3780  int main(int argc, const char ** argv) {
3780        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3781        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3782        "template"), NULL },        "template"), NULL },
3783     { "debug", 0, 0, &debug, 0,
3784        _("print debugging information for failures") },
3785   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3786      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3787     { "default-index", 0, 0, &displayDefaultIndex, 0,
3788        _("display the index of the default kernel") },
3789     { "default-title", 0, 0, &displayDefaultTitle, 0,
3790        _("display the title of the default kernel") },
3791   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3792      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3793     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3794        _("configure extlinux bootloader (from syslinux)") },
3795   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3796      _("configure grub bootloader") },      _("configure grub bootloader") },
3797     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3798        _("configure grub2 bootloader") },
3799   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3800      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3801      _("kernel-path") },      _("kernel-path") },
3802   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3803      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3804     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3805        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3806   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3807      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3808   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3822  int main(int argc, const char ** argv) {
3822   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3823      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3824        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3825     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3826        _("make the given entry index the default entry"),
3827        _("entry-index") },
3828   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3829      _("configure silo bootloader") },      _("configure silo bootloader") },
3830   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3842  int main(int argc, const char ** argv) {
3842   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3843      };      };
3844    
3845        useextlinuxmenu=0;
3846    
3847        signal(SIGSEGV, traceback);
3848    
3849      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3850      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3851    
# Line 2391  int main(int argc, const char ** argv) { Line 3855  int main(int argc, const char ** argv) {
3855      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3856      exit(0);      exit(0);
3857      break;      break;
3858      case 'i':
3859        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3860         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3861        } else {
3862     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3863     return 1;
3864        }
3865        break;
3866   }   }
3867      }      }
3868    
# Line 2406  int main(int argc, const char ** argv) { Line 3878  int main(int argc, const char ** argv) {
3878   return 1;   return 1;
3879      }      }
3880    
3881      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3882   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3883     configureExtLinux ) > 1) {
3884   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3885   return 1;   return 1;
3886      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3887   fprintf(stderr,   fprintf(stderr,
3888      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3889   return 1;   return 1;
3890        } else if (configureGrub2) {
3891     cfi = &grub2ConfigType;
3892      } else if (configureLilo) {      } else if (configureLilo) {
3893   cfi = &liloConfigType;   cfi = &liloConfigType;
3894      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3901  int main(int argc, const char ** argv) {
3901          cfi = &siloConfigType;          cfi = &siloConfigType;
3902      } else if (configureZipl) {      } else if (configureZipl) {
3903          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3904        } else if (configureExtLinux) {
3905     cfi = &extlinuxConfigType;
3906     useextlinuxmenu=1;
3907      }      }
3908    
3909      if (!cfi) {      if (!cfi) {
3910            if (grub2FindConfig(&grub2ConfigType))
3911        cfi = &grub2ConfigType;
3912     else
3913        #ifdef __ia64__        #ifdef __ia64__
3914   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3915        #elif __powerpc__        #elif __powerpc__
3916   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3917        #elif __sparc__        #elif __sparc__
3918          cfi = &siloConfigType;              cfi = &siloConfigType;
3919        #elif __s390__        #elif __s390__
3920          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3921        #elif __s390x__        #elif __s390x__
3922          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3923        #else        #else
3924   cfi = &grubConfigType;      cfi = &grubConfigType;
3925        #endif        #endif
3926      }      }
3927    
3928      if (!grubConfig)      if (!grubConfig) {
3929   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3930        grubConfig = cfi->findConfig(cfi);
3931     if (!grubConfig)
3932        grubConfig = cfi->defaultConfig;
3933        }
3934    
3935      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3936    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
3937    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
3938        (defaultIndex >= 0))) {
3939   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3940    "specified option"));    "specified option"));
3941   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3951  int main(int argc, const char ** argv) {
3951      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3952   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3953   return 1;   return 1;
3954      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3955    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3956    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3957   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3958   return 1;   return 1;
3959      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 3977  int main(int argc, const char ** argv) {
3977   makeDefault = 1;   makeDefault = 1;
3978   defaultKernel = NULL;   defaultKernel = NULL;
3979      }      }
3980        else if (defaultKernel && (defaultIndex >= 0)) {
3981     fprintf(stderr, _("grubby: --set-default and --set-default-index "
3982      "may not be used together\n"));
3983     return 1;
3984        }
3985    
3986      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3987   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3988   "is used\n"));   "is used\n"));
3989   return 1;   return 1;
3990      }      }
3991    
3992      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3993   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3994          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
3995     && (defaultIndex == -1)) {
3996   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3997   return 1;   return 1;
3998      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4012  int main(int argc, const char ** argv) {
4012   bootPrefix = "";   bootPrefix = "";
4013      }      }
4014    
4015        if (!cfi->mbAllowExtraInitRds &&
4016     extraInitrdCount > 0) {
4017     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4018     return 1;
4019        }
4020    
4021      if (bootloaderProbe) {      if (bootloaderProbe) {
4022   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4023   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4024    
4025     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4026     if (grub2config) {
4027        gconfig = readConfig(grub2config, &grub2ConfigType);
4028        if (!gconfig)
4029     gr2c = 1;
4030        else
4031     gr2c = checkForGrub2(gconfig);
4032     }
4033    
4034   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4035      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4036        gconfig = readConfig(grubconfig, &grubConfigType);
4037      if (!gconfig)      if (!gconfig)
4038   grc = 1;   grc = 1;
4039      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4048  int main(int argc, const char ** argv) {
4048   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4049   }   }
4050    
4051   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4052        econfig = readConfig(eliloConfigType.defaultConfig,
4053     &eliloConfigType);
4054        if (!econfig)
4055     erc = 1;
4056        else
4057     erc = checkForElilo(econfig);
4058     }
4059    
4060     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4061        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4062        if (!lconfig)
4063     extrc = 1;
4064        else
4065     extrc = checkForExtLinux(lconfig);
4066     }
4067    
4068    
4069     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4070        yconfig = readConfig(yabootConfigType.defaultConfig,
4071     &yabootConfigType);
4072        if (!yconfig)
4073     yrc = 1;
4074        else
4075     yrc = checkForYaboot(yconfig);
4076     }
4077    
4078     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4079     erc == 1)
4080        return 1;
4081    
4082   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4083     if (gr2c == 2) printf("grub2\n");
4084   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4085     if (extrc == 2) printf("extlinux\n");
4086     if (yrc == 2) printf("yaboot\n");
4087     if (erc == 2) printf("elilo\n");
4088    
4089   return 0;   return 0;
4090      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4102  int main(int argc, const char ** argv) {
4102   if (!entry) return 0;   if (!entry) return 0;
4103   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4104    
4105   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4106   if (!line) return 0;   if (!line) return 0;
4107    
4108          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4110  int main(int argc, const char ** argv) {
4110                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4111    
4112   return 0;   return 0;
4113    
4114        } else if (displayDefaultTitle) {
4115     struct singleLine * line;
4116     struct singleEntry * entry;
4117    
4118     if (config->defaultImage == -1) return 0;
4119     entry = findEntryByIndex(config, config->defaultImage);
4120     if (!entry) return 0;
4121    
4122     if (!configureGrub2) {
4123      line = getLineByType(LT_TITLE, entry->lines);
4124      if (!line) return 0;
4125      printf("%s\n", line->elements[1].item);
4126    
4127     } else {
4128      char * title;
4129    
4130      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4131      line = getLineByType(LT_MENUENTRY, entry->lines);
4132      if (!line) return 0;
4133      title = grub2ExtractTitle(line);
4134      if (title)
4135        printf("%s\n", title);
4136     }
4137     return 0;
4138    
4139        } else if (displayDefaultIndex) {
4140            if (config->defaultImage == -1) return 0;
4141            printf("%i\n", config->defaultImage);
4142    
4143      } else if (kernelInfo)      } else if (kernelInfo)
4144   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4145    
# Line 2581  int main(int argc, const char ** argv) { Line 4151  int main(int argc, const char ** argv) {
4151      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4152      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4153      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4154      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4155      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4156      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4157                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4158        if (updateKernelPath && newKernelInitrd) {
4159                if (updateInitrd(config, updateKernelPath, bootPrefix,
4160                                 newKernelInitrd)) return 1;
4161        }
4162      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4163                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4164                         (const char **)extraInitrds, extraInitrdCount,
4165                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4166            
4167    
# Line 2597  int main(int argc, const char ** argv) { Line 4172  int main(int argc, const char ** argv) {
4172      }      }
4173    
4174      if (!outputFile)      if (!outputFile)
4175   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4176    
4177      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4178  }  }

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