Magellan Linux

Diff of /tags/grubby-8_34/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 2255 by niro, Mon Oct 21 14:00:38 2013 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    #include "log.h"
40    
41    #ifndef DEBUG
42    #define DEBUG 0
43    #endif
44    
45    #if DEBUG
46    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
47    #else
48    #define dbgPrintf(format, args...)
49    #endif
50    
51  #include "mount_by_label.h"  int debug = 0; /* Currently just for template debugging */
52    
53  #define _(A) (A)  #define _(A) (A)
54    
55    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
56  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
57    
58    #define NOOP_OPCODE 0x90
59    #define JMP_SHORT_OPCODE 0xeb
60    
61    int isEfi = 0;
62    
63    char *saved_command_line = NULL;
64    
65  /* comments get lumped in with indention */  /* comments get lumped in with indention */
66  struct lineElement {  struct lineElement {
67      char * item;      char * item;
68      char * indent;      char * indent;
69  };  };
70    
71  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
72         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
73         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
74        LT_KERNEL       = 1 << 2,
75        LT_INITRD       = 1 << 3,
76        LT_HYPER        = 1 << 4,
77        LT_DEFAULT      = 1 << 5,
78        LT_MBMODULE     = 1 << 6,
79        LT_ROOT         = 1 << 7,
80        LT_FALLBACK     = 1 << 8,
81        LT_KERNELARGS   = 1 << 9,
82        LT_BOOT         = 1 << 10,
83        LT_BOOTROOT     = 1 << 11,
84        LT_LBA          = 1 << 12,
85        LT_OTHER        = 1 << 13,
86        LT_GENERIC      = 1 << 14,
87        LT_ECHO    = 1 << 16,
88        LT_MENUENTRY    = 1 << 17,
89        LT_ENTRY_END    = 1 << 18,
90        LT_SET_VARIABLE = 1 << 19,
91        LT_KERNEL_EFI   = 1 << 20,
92        LT_INITRD_EFI   = 1 << 21,
93        LT_UNKNOWN      = 1 << 22,
94    };
95    
96  struct singleLine {  struct singleLine {
97      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 112  struct singleEntry {
112    
113  #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 */
114    
115  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
116  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
117  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
118  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
119  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
120    #define NEED_MB      (1 << 4)
121    #define NEED_END     (1 << 5)
122    
123  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
124  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
125    #define DEFAULT_SAVED_GRUB2 -3
126    
127  struct keywordTypes {  struct keywordTypes {
128      char * key;      char * key;
129      enum lineType_e type;      enum lineType_e type;
130      char nextChar;      char nextChar;
131  } ;      char separatorChar;
132    };
133    
134    struct configFileInfo;
135    
136    typedef const char *(*findConfigFunc)(struct configFileInfo *);
137    typedef const int (*writeLineFunc)(struct configFileInfo *,
138     struct singleLine *line);
139    typedef char *(*getEnvFunc)(struct configFileInfo *, char *name);
140    typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value);
141    
142  struct configFileInfo {  struct configFileInfo {
143      char * defaultConfig;      char * defaultConfig;
144        findConfigFunc findConfig;
145        writeLineFunc writeLine;
146        getEnvFunc getEnv;
147        setEnvFunc setEnv;
148      struct keywordTypes * keywords;      struct keywordTypes * keywords;
149        int caseInsensitive;
150      int defaultIsIndex;      int defaultIsIndex;
151        int defaultIsVariable;
152      int defaultSupportSaved;      int defaultSupportSaved;
153      enum lineType_e entrySeparator;      int defaultIsSaved;
154        enum lineType_e entryStart;
155        enum lineType_e entryEnd;
156      int needsBootPrefix;      int needsBootPrefix;
157      int argsInQuotes;      int argsInQuotes;
158      int maxTitleLength;      int maxTitleLength;
159      int titleBracketed;      int titleBracketed;
160        int titlePosition;
161        int mbHyperFirst;
162        int mbInitRdIsModule;
163        int mbConcatArgs;
164        int mbAllowExtraInitRds;
165        char *envFile;
166  };  };
167    
168  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 171  struct keywordTypes grubKeywords[] = {
171      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
172      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
173      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
174      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
175      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
176        { "kernel",     LT_HYPER,       ' ' },
177      { NULL,    0, 0 },      { NULL,    0, 0 },
178  };  };
179    
180    const char *grubFindConfig(struct configFileInfo *cfi) {
181        static const char *configFiles[] = {
182     "/boot/grub/grub.conf",
183     "/boot/grub/menu.lst",
184     "/etc/grub.conf",
185     NULL
186        };
187        static int i = -1;
188    
189        if (i == -1) {
190     for (i = 0; configFiles[i] != NULL; i++) {
191        dbgPrintf("Checking \"%s\": ", configFiles[i]);
192        if (!access(configFiles[i], R_OK)) {
193     dbgPrintf("found\n");
194     return configFiles[i];
195        }
196        dbgPrintf("not found\n");
197     }
198        }
199        return configFiles[i];
200    }
201    
202  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
203      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
204      grubKeywords,    /* keywords */      .keywords = grubKeywords,
205      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
206      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
207      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
208      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
209      0,    /* argsInQuotes */      .mbHyperFirst = 1,
210      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
211      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
212    };
213    
214    struct keywordTypes grub2Keywords[] = {
215        { "menuentry",  LT_MENUENTRY,   ' ' },
216        { "}",          LT_ENTRY_END,   ' ' },
217        { "echo",       LT_ECHO,        ' ' },
218        { "set",        LT_SET_VARIABLE,' ', '=' },
219        { "root",       LT_BOOTROOT,    ' ' },
220        { "default",    LT_DEFAULT,     ' ' },
221        { "fallback",   LT_FALLBACK,    ' ' },
222        { "linux",      LT_KERNEL,      ' ' },
223        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
224        { "initrd",     LT_INITRD,      ' ', ' ' },
225        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
226        { "module",     LT_MBMODULE,    ' ' },
227        { "kernel",     LT_HYPER,       ' ' },
228        { NULL, 0, 0 },
229    };
230    
231    const char *grub2FindConfig(struct configFileInfo *cfi) {
232        static const char *configFiles[] = {
233     "/boot/grub/grub-efi.cfg",
234     "/boot/grub/grub.cfg",
235     NULL
236        };
237        static int i = -1;
238        static const char *grub_cfg = "/boot/grub/grub.cfg";
239        int rc = -1;
240    
241        if (i == -1) {
242     for (i = 0; configFiles[i] != NULL; i++) {
243        dbgPrintf("Checking \"%s\": ", configFiles[i]);
244        if ((rc = access(configFiles[i], R_OK))) {
245     if (errno == EACCES) {
246        printf("Unable to access bootloader configuration file "
247           "\"%s\": %m\n", configFiles[i]);
248        exit(1);
249     }
250     continue;
251        } else {
252     dbgPrintf("found\n");
253     return configFiles[i];
254        }
255     }
256        }
257    
258        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
259         * that isn't in grub1, and if it exists, return the config file path
260         * that they use. */
261        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
262     dbgPrintf("found\n");
263     return grub_cfg;
264        }
265    
266        dbgPrintf("not found\n");
267        return configFiles[i];
268    }
269    
270    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
271    static char *grub2GetEnv(struct configFileInfo *info, char *name)
272    {
273        static char buf[1025];
274        char *s = NULL;
275        char *ret = NULL;
276        char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
277        int rc = asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name);
278    
279        if (rc < 0)
280     return NULL;
281    
282        FILE *f = popen(s, "r");
283        if (!f)
284     goto out;
285    
286        memset(buf, '\0', sizeof (buf));
287        ret = fgets(buf, 1024, f);
288        pclose(f);
289    
290        if (ret) {
291     ret += strlen(name) + 1;
292     ret[strlen(ret) - 1] = '\0';
293        }
294        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
295    out:
296        free(s);
297        return ret;
298    }
299    
300    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
301    {
302        char *s = NULL;
303        int rc = 0;
304        char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
305    
306        rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value);
307        if (rc <0)
308     return -1;
309    
310        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
311        rc = system(s);
312        free(s);
313        return rc;
314    }
315    
316    /* this is a gigantic hack to avoid clobbering grub2 variables... */
317    static int is_special_grub2_variable(const char *name)
318    {
319        if (!strcmp(name,"\"${next_entry}\""))
320     return 1;
321        if (!strcmp(name,"\"${prev_saved_entry}\""))
322     return 1;
323        return 0;
324    }
325    
326    int sizeOfSingleLine(struct singleLine * line) {
327      int count = 0;
328    
329      for (int i = 0; i < line->numElements; i++) {
330        int indentSize = 0;
331    
332        count = count + strlen(line->elements[i].item);
333    
334        indentSize = strlen(line->elements[i].indent);
335        if (indentSize > 0)
336          count = count + indentSize;
337        else
338          /* be extra safe and add room for whitespaces */
339          count = count + 1;
340      }
341    
342      /* room for trailing terminator */
343      count = count + 1;
344    
345      return count;
346    }
347    
348    static int isquote(char q)
349    {
350        if (q == '\'' || q == '\"')
351     return 1;
352        return 0;
353    }
354    
355    static int iskernel(enum lineType_e type) {
356        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
357    }
358    
359    static int isinitrd(enum lineType_e type) {
360        return (type == LT_INITRD || type == LT_INITRD_EFI);
361    }
362    
363    char *grub2ExtractTitle(struct singleLine * line) {
364        char * current;
365        char * current_indent;
366        int current_len;
367        int current_indent_len;
368        int i;
369    
370        /* bail out if line does not start with menuentry */
371        if (strcmp(line->elements[0].item, "menuentry"))
372          return NULL;
373    
374        i = 1;
375        current = line->elements[i].item;
376        current_len = strlen(current);
377    
378        /* if second word is quoted, strip the quotes and return single word */
379        if (isquote(*current) && isquote(current[current_len - 1])) {
380     char *tmp;
381    
382     tmp = strdup(current);
383     *(tmp + current_len - 1) = '\0';
384     return ++tmp;
385        }
386    
387        /* if no quotes, return second word verbatim */
388        if (!isquote(*current))
389     return current;
390    
391        /* second element start with a quote, so we have to find the element
392         * whose last character is also quote (assuming it's the closing one) */
393        int resultMaxSize;
394        char * result;
395        
396        resultMaxSize = sizeOfSingleLine(line);
397        result = malloc(resultMaxSize);
398        snprintf(result, resultMaxSize, "%s", ++current);
399        
400        i++;
401        for (; i < line->numElements; ++i) {
402     current = line->elements[i].item;
403     current_len = strlen(current);
404     current_indent = line->elements[i].indent;
405     current_indent_len = strlen(current_indent);
406    
407     strncat(result, current_indent, current_indent_len);
408     if (!isquote(current[current_len-1])) {
409        strncat(result, current, current_len);
410     } else {
411        strncat(result, current, current_len - 1);
412        break;
413     }
414        }
415        return result;
416    }
417    
418    struct configFileInfo grub2ConfigType = {
419        .findConfig = grub2FindConfig,
420        .getEnv = grub2GetEnv,
421        .setEnv = grub2SetEnv,
422        .keywords = grub2Keywords,
423        .defaultIsIndex = 1,
424        .defaultSupportSaved = 1,
425        .defaultIsVariable = 1,
426        .entryStart = LT_MENUENTRY,
427        .entryEnd = LT_ENTRY_END,
428        .titlePosition = 1,
429        .needsBootPrefix = 1,
430        .mbHyperFirst = 1,
431        .mbInitRdIsModule = 1,
432        .mbAllowExtraInitRds = 1,
433  };  };
434    
435  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 463  struct keywordTypes yabootKeywords[] = {
463      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
464      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
465      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
466      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
467      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
468      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
469      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 483  struct keywordTypes liloKeywords[] = {
483      { NULL,    0, 0 },      { NULL,    0, 0 },
484  };  };
485    
486    struct keywordTypes eliloKeywords[] = {
487        { "label",    LT_TITLE,    '=' },
488        { "root",    LT_ROOT,    '=' },
489        { "default",    LT_DEFAULT,    '=' },
490        { "image",    LT_KERNEL,    '=' },
491        { "initrd",    LT_INITRD,    '=' },
492        { "append",    LT_KERNELARGS,  '=' },
493        { "vmm",    LT_HYPER,       '=' },
494        { NULL,    0, 0 },
495    };
496    
497  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
498      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
499      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 515  struct keywordTypes ziplKeywords[] = {
515      { NULL,         0, 0 },      { NULL,         0, 0 },
516  };  };
517    
518    struct keywordTypes extlinuxKeywords[] = {
519        { "label",    LT_TITLE,    ' ' },
520        { "root",    LT_ROOT,    ' ' },
521        { "default",    LT_DEFAULT,    ' ' },
522        { "kernel",    LT_KERNEL,    ' ' },
523        { "initrd",    LT_INITRD,      ' ', ',' },
524        { "append",    LT_KERNELARGS,  ' ' },
525        { "prompt",     LT_UNKNOWN,     ' ' },
526        { NULL,    0, 0 },
527    };
528    int useextlinuxmenu;
529  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
530      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
531      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
532      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
533      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
534      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
535      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
536  };  };
537    
538  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
539      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
540      liloKeywords,    /* keywords */      .keywords = liloKeywords,
541      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
542      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
543      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
544  };  };
545    
546  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
547      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
548      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
549      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
550      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
551      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
552      1,    /* needsBootPrefix */      .maxTitleLength = 15,
553      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
554  };  };
555    
556  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
557      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
558      siloKeywords,    /* keywords */      .keywords = siloKeywords,
559      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
560      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
561      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
562      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
563  };  };
564    
565  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
566      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
567      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
568      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
569      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
570      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
571      0,    /* needsBootPrefix */  };
572      1,    /* argsInQuotes */  
573      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
574      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
575        .keywords = extlinuxKeywords,
576        .caseInsensitive = 1,
577        .entryStart = LT_TITLE,
578        .needsBootPrefix = 1,
579        .maxTitleLength = 255,
580        .mbAllowExtraInitRds = 1,
581  };  };
582    
583  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 592  struct grubConfig {
592      struct configFileInfo * cfi;      struct configFileInfo * cfi;
593  };  };
594    
595    blkid_cache blkid;
596    
597  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
598  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
599       const char * path, const char * prefix,       const char * path, const char * prefix,
600       int * index);       int * index);
601  static char * strndup(char * from, int len);  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
602          int * index);
603  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
604  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
605    struct singleLine * lineDup(struct singleLine * line);
606  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
607  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
608       struct configFileInfo * cfi);       struct configFileInfo * cfi);
609  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
610         struct configFileInfo * cfi);         struct configFileInfo * cfi);
611  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
612    static void requote(struct singleLine *line, struct configFileInfo * cfi);
613  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
614      char * to;    const char * item, int insertHere,
615      struct configFileInfo * cfi);
616      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
617      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
618      to[len] = '\0';        struct configFileInfo * cfi);
619    static enum lineType_e getTypeByKeyword(char * keyword,
620      return to;   struct configFileInfo * cfi);
621  }  static struct singleLine * getLineByType(enum lineType_e type,
622     struct singleLine * line);
623    static int checkForExtLinux(struct grubConfig * config);
624    struct singleLine * addLineTmpl(struct singleEntry * entry,
625                                    struct singleLine * tmplLine,
626                                    struct singleLine * prevLine,
627                                    const char * val,
628     struct configFileInfo * cfi);
629    struct singleLine *  addLine(struct singleEntry * entry,
630                                 struct configFileInfo * cfi,
631                                 enum lineType_e type, char * defaultIndent,
632                                 const char * val);
633    
634  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
635  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 664  static char * sdupprintf(const char *for
664      return buf;      return buf;
665  }  }
666    
667    static enum lineType_e preferredLineType(enum lineType_e type,
668     struct configFileInfo *cfi) {
669        if (isEfi && cfi == &grub2ConfigType) {
670     switch (type) {
671     case LT_KERNEL:
672        return LT_KERNEL_EFI;
673     case LT_INITRD:
674        return LT_INITRD_EFI;
675     default:
676        return type;
677     }
678        }
679        return type;
680    }
681    
682    static struct keywordTypes * getKeywordByType(enum lineType_e type,
683          struct configFileInfo * cfi) {
684        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
685     if (kw->type == type)
686        return kw;
687        }
688        return NULL;
689    }
690    
691    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
692        struct keywordTypes *kt = getKeywordByType(type, cfi);
693        if (kt)
694     return kt->key;
695        return "unknown";
696    }
697    
698    static char * getpathbyspec(char *device) {
699        if (!blkid)
700            blkid_get_cache(&blkid, NULL);
701    
702        return blkid_get_devname(blkid, device, NULL);
703    }
704    
705    static char * getuuidbydev(char *device) {
706        if (!blkid)
707     blkid_get_cache(&blkid, NULL);
708    
709        return blkid_get_tag_value(blkid, "UUID", device);
710    }
711    
712    static enum lineType_e getTypeByKeyword(char * keyword,
713     struct configFileInfo * cfi) {
714        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
715     if (cfi->caseInsensitive) {
716        if (!strcasecmp(keyword, kw->key))
717                    return kw->type;
718     } else {
719        if (!strcmp(keyword, kw->key))
720            return kw->type;
721     }
722        }
723        return LT_UNKNOWN;
724    }
725    
726    static struct singleLine * getLineByType(enum lineType_e type,
727     struct singleLine * line) {
728        dbgPrintf("getLineByType(%d): ", type);
729        for (; line; line = line->next) {
730     dbgPrintf("%d:%s ", line->type,
731      line->numElements ? line->elements[0].item : "(empty)");
732     if (line->type & type) break;
733        }
734        dbgPrintf(line ? "\n" : " (failed)\n");
735        return line;
736    }
737    
738  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
739      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
740          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
741          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
742              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 748  static int isBracketedTitle(struct singl
748      return 0;      return 0;
749  }  }
750    
751  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
752                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
753      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
754   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;  
755  }  }
756    
757  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
758  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
759      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
760      char * title;      char * title = NULL;
761      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
762      title++;   title = strdup(line->elements[0].item);
763      *(title + strlen(title) - 1) = '\0';   title++;
764     *(title + strlen(title) - 1) = '\0';
765        } else if (line->type == LT_MENUENTRY)
766     title = strdup(line->elements[1].item);
767        else
768     return NULL;
769      return title;      return title;
770  }  }
771    
# Line 389  static void lineInit(struct singleLine * Line 807  static void lineInit(struct singleLine *
807      line->next = NULL;      line->next = NULL;
808  }  }
809    
810  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
811      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
812    
813        newLine->indent = strdup(line->indent);
814        newLine->next = NULL;
815        newLine->type = line->type;
816        newLine->numElements = line->numElements;
817        newLine->elements = malloc(sizeof(*newLine->elements) *
818           newLine->numElements);
819    
820        for (int i = 0; i < newLine->numElements; i++) {
821     newLine->elements[i].indent = strdup(line->elements[i].indent);
822     newLine->elements[i].item = strdup(line->elements[i].item);
823        }
824    
825        return newLine;
826    }
827    
828    static void lineFree(struct singleLine * line) {
829      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
830    
831      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
832   free(line->elements[i].item);   free(line->elements[i].item);
833   free(line->elements[i].indent);   free(line->elements[i].indent);
834      }      }
# Line 405  static void lineFree(struct singleLine * Line 839  static void lineFree(struct singleLine *
839    
840  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
841       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
842      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
843    
844      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
845     /* Need to handle this, because we strip the quotes from
846     * menuentry when read it. */
847     if (line->type == LT_MENUENTRY && i == 1) {
848        if(!isquote(*line->elements[i].item))
849     fprintf(out, "\'%s\'", line->elements[i].item);
850        else
851     fprintf(out, "%s", line->elements[i].item);
852        fprintf(out, "%s", line->elements[i].indent);
853    
854        continue;
855     }
856    
857   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
858      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
859    
860   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
861   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
862        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
863      }      }
864    
865      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 878  static int getNextLine(char ** bufPtr, s
878      char * chptr;      char * chptr;
879      int elementsAlloced = 0;      int elementsAlloced = 0;
880      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
881      int first = 1;      int first = 1;
     int i;  
882    
883      lineFree(line);      lineFree(line);
884    
# Line 489  static int getNextLine(char ** bufPtr, s Line 932  static int getNextLine(char ** bufPtr, s
932      if (!line->numElements)      if (!line->numElements)
933   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
934      else {      else {
935   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
936      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;  
               
937              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
938               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
939              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 947  static int getNextLine(char ** bufPtr, s
947      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
948   char * fullLine;   char * fullLine;
949   int len;   int len;
  int i;  
950    
951   len = strlen(line->indent);   len = strlen(line->indent);
952   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
953      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
954     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
955    
# Line 522  static int getNextLine(char ** bufPtr, s Line 958  static int getNextLine(char ** bufPtr, s
958   free(line->indent);   free(line->indent);
959   line->indent = fullLine;   line->indent = fullLine;
960    
961   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
962      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
963      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
964      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 968  static int getNextLine(char ** bufPtr, s
968   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
969   line->numElements = 0;   line->numElements = 0;
970      }      }
971     } else {
972     struct keywordTypes *kw;
973    
974     kw = getKeywordByType(line->type, cfi);
975    
976     /* space isn't the only separator, we need to split
977     * elements up more
978     */
979     if (!isspace(kw->separatorChar)) {
980        char indent[2] = "";
981        indent[0] = kw->separatorChar;
982        for (int i = 1; i < line->numElements; i++) {
983     char *p;
984     int numNewElements;
985    
986     numNewElements = 0;
987     p = line->elements[i].item;
988     while (*p != '\0') {
989     if (*p == kw->separatorChar)
990     numNewElements++;
991     p++;
992     }
993     if (line->numElements + numNewElements >= elementsAlloced) {
994     elementsAlloced += numNewElements + 5;
995     line->elements = realloc(line->elements,
996        sizeof(*line->elements) * elementsAlloced);
997     }
998    
999     for (int j = line->numElements; j > i; j--) {
1000     line->elements[j + numNewElements] = line->elements[j];
1001     }
1002     line->numElements += numNewElements;
1003    
1004     p = line->elements[i].item;
1005     while (*p != '\0') {
1006    
1007     while (*p != kw->separatorChar && *p != '\0') p++;
1008     if (*p == '\0') {
1009     break;
1010     }
1011    
1012     line->elements[i + 1].indent = line->elements[i].indent;
1013     line->elements[i].indent = strdup(indent);
1014     *p++ = '\0';
1015     i++;
1016     line->elements[i].item = strdup(p);
1017     }
1018        }
1019     }
1020   }   }
1021      }      }
1022    
# Line 549  static struct grubConfig * readConfig(co Line 1034  static struct grubConfig * readConfig(co
1034      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1035      char * end;      char * end;
1036      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1037      int i, len;      int len;
1038      char * buf;      char * buf;
1039    
1040      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1041            printf("Could not find bootloader configuration\n");
1042            exit(1);
1043        } else if (!strcmp(inName, "-")) {
1044   in = 0;   in = 0;
1045      } else {      } else {
1046   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1083  static struct grubConfig * readConfig(co
1083      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1084   }   }
1085    
1086   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1087      sawEntry = 1;      sawEntry = 1;
1088      if (!entry) {      if (!entry) {
1089   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1099  static struct grubConfig * readConfig(co
1099      entry->next = NULL;      entry->next = NULL;
1100   }   }
1101    
1102   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1103        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1104        dbgPrintf("%s", line->indent);
1105        for (int i = 0; i < line->numElements; i++)
1106     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1107        dbgPrintf("\n");
1108        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1109        if (kwType && line->numElements == 3 &&
1110        !strcmp(line->elements[1].item, kwType->key) &&
1111        !is_special_grub2_variable(line->elements[2].item)) {
1112     dbgPrintf("Line sets default config\n");
1113     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1114     defaultLine = line;
1115        }
1116     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1117      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1118      defaultLine = line;      defaultLine = line;
1119    
1120            } else if (iskernel(line->type)) {
1121        /* if by some freak chance this is multiboot and the "module"
1122         * lines came earlier in the template, make sure to use LT_HYPER
1123         * instead of LT_KERNEL now
1124         */
1125        if (entry->multiboot)
1126     line->type = LT_HYPER;
1127    
1128          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1129        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1130         * instead, now that we know this is a multiboot entry.
1131         * This only applies to grub, but that's the only place we
1132         * should find LT_MBMODULE lines anyway.
1133         */
1134        for (struct singleLine *l = entry->lines; l; l = l->next) {
1135     if (l->type == LT_HYPER)
1136        break;
1137     else if (iskernel(l->type)) {
1138        l->type = LT_HYPER;
1139        break;
1140     }
1141        }
1142              entry->multiboot = 1;              entry->multiboot = 1;
1143    
1144     } else if (line->type == LT_HYPER) {
1145        entry->multiboot = 1;
1146    
1147   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1148      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1149      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1150    
1151   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1152      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1153      len = 0;      len = 0;
1154      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1155   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1156   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1157      }      }
1158      buf = malloc(len + 1);      buf = malloc(len + 1);
1159      *buf = '\0';      *buf = '\0';
1160    
1161      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1162   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1163   free(line->elements[i].item);   free(line->elements[i].item);
1164    
# Line 643  static struct grubConfig * readConfig(co Line 1172  static struct grubConfig * readConfig(co
1172      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1173      line->elements[1].item = buf;      line->elements[1].item = buf;
1174      line->numElements = 2;      line->numElements = 2;
1175     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1176        /* let --remove-kernel="TITLE=what" work */
1177        len = 0;
1178        char *extras;
1179        char *title;
1180    
1181        for (int i = 1; i < line->numElements; i++) {
1182     len += strlen(line->elements[i].item);
1183     len += strlen(line->elements[i].indent);
1184        }
1185        buf = malloc(len + 1);
1186        *buf = '\0';
1187    
1188        /* allocate mem for extra flags. */
1189        extras = malloc(len + 1);
1190        *extras = '\0';
1191    
1192        /* get title. */
1193        for (int i = 0; i < line->numElements; i++) {
1194     if (!strcmp(line->elements[i].item, "menuentry"))
1195        continue;
1196     if (isquote(*line->elements[i].item))
1197        title = line->elements[i].item + 1;
1198     else
1199        title = line->elements[i].item;
1200    
1201     len = strlen(title);
1202            if (isquote(title[len-1])) {
1203        strncat(buf, title,len-1);
1204        break;
1205     } else {
1206        strcat(buf, title);
1207        strcat(buf, line->elements[i].indent);
1208     }
1209        }
1210    
1211        /* get extras */
1212        int count = 0;
1213        for (int i = 0; i < line->numElements; i++) {
1214     if (count >= 2) {
1215        strcat(extras, line->elements[i].item);
1216        strcat(extras, line->elements[i].indent);
1217     }
1218    
1219     if (!strcmp(line->elements[i].item, "menuentry"))
1220        continue;
1221    
1222     /* count ' or ", there should be two in menuentry line. */
1223     if (isquote(*line->elements[i].item))
1224        count++;
1225    
1226     len = strlen(line->elements[i].item);
1227    
1228     if (isquote(line->elements[i].item[len -1]))
1229        count++;
1230    
1231     /* ok, we get the final ' or ", others are extras. */
1232                }
1233        line->elements[1].indent =
1234     line->elements[line->numElements - 2].indent;
1235        line->elements[1].item = buf;
1236        line->elements[2].indent =
1237     line->elements[line->numElements - 2].indent;
1238        line->elements[2].item = extras;
1239        line->numElements = 3;
1240   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1241      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1242         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 1245  static struct grubConfig * readConfig(co
1245      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1246   int last, len;   int last, len;
1247    
1248   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1249      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1250     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1251    
1252   last = line->numElements - 1;   last = line->numElements - 1;
1253   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1254   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1255      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1256      }      }
   
1257   }   }
1258    
1259   /* 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 1273  static struct grubConfig * readConfig(co
1273   movedLine = 1;   movedLine = 1;
1274   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1275   }   }
1276    
1277   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1278     which was moved, drop it. */     which was moved, drop it. */
1279   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 1289  static struct grubConfig * readConfig(co
1289   entry->lines = line;   entry->lines = line;
1290      else      else
1291   last->next = line;   last->next = line;
1292        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1293    
1294        /* we could have seen this outside of an entry... if so, we
1295         * ignore it like any other line we don't grok */
1296        if (line->type == LT_ENTRY_END && sawEntry)
1297     sawEntry = 0;
1298   } else {   } else {
1299      if (!cfg->theLines)      if (!cfg->theLines)
1300   cfg->theLines = line;   cfg->theLines = line;
1301      else {      else
1302   last->next = line;   last->next = line;
1303      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1304   }   }
1305    
1306   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1308  static struct grubConfig * readConfig(co
1308    
1309      free(incoming);      free(incoming);
1310    
1311        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1312      if (defaultLine) {      if (defaultLine) {
1313   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1314        cfi->defaultSupportSaved &&
1315        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1316     cfg->cfi->defaultIsSaved = 1;
1317     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1318     if (cfg->cfi->getEnv) {
1319        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1320        if (defTitle) {
1321     int index = 0;
1322     entry = findEntryByTitle(cfg, defTitle, &index);
1323     if (entry)
1324        cfg->defaultImage = index;
1325        }
1326     }
1327     } else if (cfi->defaultIsVariable) {
1328        char *value = defaultLine->elements[2].item;
1329        while (*value && (*value == '"' || *value == '\'' ||
1330        *value == ' ' || *value == '\t'))
1331     value++;
1332        cfg->defaultImage = strtol(value, &end, 10);
1333        while (*end && (*end == '"' || *end == '\'' ||
1334        *end == ' ' || *end == '\t'))
1335     end++;
1336        if (*end) cfg->defaultImage = -1;
1337     } else if (cfi->defaultSupportSaved &&
1338   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1339      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1340   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1341      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1342      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1343   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1344      i = 0;      int i = 0;
1345      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1346   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1347      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1355  static struct grubConfig * readConfig(co
1355                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1356                  }                  }
1357   i++;   i++;
1358     entry = NULL;
1359      }      }
1360    
1361      if (entry) cfg->defaultImage = i;      if (entry){
1362            cfg->defaultImage = i;
1363        }else{
1364            cfg->defaultImage = -1;
1365        }
1366     }
1367        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1368     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1369     if (defTitle) {
1370        int index = 0;
1371        entry = findEntryByTitle(cfg, defTitle, &index);
1372        if (entry)
1373     cfg->defaultImage = index;
1374   }   }
1375        } else {
1376            cfg->defaultImage = 0;
1377      }      }
1378    
1379      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1389  static void writeDefault(FILE * out, cha
1389    
1390      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1391   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1392      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1393     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1394     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1395        char *title;
1396        entry = findEntryByIndex(cfg, cfg->defaultImage);
1397        line = getLineByType(LT_MENUENTRY, entry->lines);
1398        if (!line)
1399     line = getLineByType(LT_TITLE, entry->lines);
1400        if (line) {
1401     title = extractTitle(line);
1402     if (title)
1403        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1404        }
1405     }
1406        } else if (cfg->defaultImage > -1) {
1407   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1408      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1409      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1410     cfg->defaultImage);
1411        } else {
1412     fprintf(out, "%sdefault%s%d\n", indent, separator,
1413     cfg->defaultImage);
1414        }
1415   } else {   } else {
1416      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1417    
# Line 769  static void writeDefault(FILE * out, cha Line 1428  static void writeDefault(FILE * out, cha
1428    
1429      if (!entry) return;      if (!entry) return;
1430    
1431      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1432    
1433      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1434   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1462  static int writeConfig(struct grubConfig
1462      int rc;      int rc;
1463    
1464      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1465         directory to / */         directory to the dir of the symlink */
1466      rc = chdir("/");      char *dir = strdupa(outName);
1467        rc = chdir(dirname(dir));
1468      do {      do {
1469   buf = alloca(len + 1);   buf = alloca(len + 1);
1470   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1471   if (rc == len) len += 256;   if (rc == len) len += 256;
1472      } while (rc == len);      } while (rc == len);
1473            
# Line 843  static int writeConfig(struct grubConfig Line 1502  static int writeConfig(struct grubConfig
1502      }      }
1503    
1504      line = cfg->theLines;      line = cfg->theLines;
1505        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1506      while (line) {      while (line) {
1507   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1508     line->numElements == 3 &&
1509     !strcmp(line->elements[1].item, defaultKw->key) &&
1510     !is_special_grub2_variable(line->elements[2].item)) {
1511        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1512        needs &= ~MAIN_DEFAULT;
1513     } else if (line->type == LT_DEFAULT) {
1514      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1515      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1516   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1578  static int numEntries(struct grubConfig
1578      return i;      return i;
1579  }  }
1580    
1581  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1582    int skipRemoved, int flags) {  {
1583      struct singleLine * line;      int fd;
1584      char * fullName;      char buf[65536];
1585      int i;      char *devname;
1586      struct stat sb, sb2;      char *chptr;
1587      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1588    
1589      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1590      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1591                        _PATH_MOUNTED, strerror(errno));
1592      if (!line) return 0;          return NULL;
1593      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1594    
1595      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1596        if (rc <= 0) {
1597            fprintf(stderr, "grubby: failed to read %s: %s\n",
1598                    _PATH_MOUNTED, strerror(errno));
1599            close(fd);
1600            return NULL;
1601        }
1602        close(fd);
1603        buf[rc] = '\0';
1604        chptr = buf;
1605    
1606      fullName = alloca(strlen(bootPrefix) +      char *foundanswer = NULL;
       strlen(line->elements[1].item) + 1);  
     rootspec = getRootSpecifier(line->elements[1].item);  
     sprintf(fullName, "%s%s", bootPrefix,  
             line->elements[1].item + ((rootspec != NULL) ?  
                                       strlen(rootspec) : 0));  
     if (access(fullName, R_OK)) return 0;  
1607    
1608      for (i = 2; i < line->numElements; i++)      while (chptr && chptr != buf+rc) {
1609   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          devname = chptr;
     if (i < line->numElements) {  
  dev = line->elements[i].item + 5;  
     } else {  
  /* look for a lilo style LT_ROOT line */  
  line = entry->lines;  
  while (line && line->type != LT_ROOT) line = line->next;  
1610    
1611   if (line && line->numElements >= 2) {          /*
1612      dev = line->elements[1].item;           * The first column of a mtab entry is the device, but if the entry is a
1613   } else {           * special device it won't start with /, so move on to the next line.
1614              int type;           */
1615      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */          if (*devname != '/') {
1616      line = entry->lines;              chptr = strchr(chptr, '\n');
1617                if (chptr)
1618                    chptr++;
1619                continue;
1620            }
1621    
1622              type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);          /* Seek to the next space */
1623            chptr = strchr(chptr, ' ');
1624            if (!chptr) {
1625                fprintf(stderr, "grubby: error parsing %s: %s\n",
1626                        _PATH_MOUNTED, strerror(errno));
1627                return NULL;
1628            }
1629    
1630      while (line && line->type != type) line = line->next;          /*
1631             * The second column of a mtab entry is the mount point, we are looking
1632             * for '/' obviously.
1633             */
1634            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1635                /* remember the last / entry in mtab */
1636               foundanswer = devname;
1637            }
1638    
1639              /* failed to find one */          /* Next line */
1640              if (!line) return 0;          chptr = strchr(chptr, '\n');
1641            if (chptr)
1642                chptr++;
1643        }
1644    
1645      for (i = 1; i < line->numElements; i++)      /* Return the last / entry found */
1646          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;      if (foundanswer) {
1647      if (i < line->numElements)          chptr = strchr(foundanswer, ' ');
1648          dev = line->elements[i].item + 5;          *chptr = '\0';
1649      else {          return strdup(foundanswer);
1650   /* it failed too...  can't find root= */      }
1651          return 0;  
1652              }      return NULL;
1653    }
1654    
1655    void printEntry(struct singleEntry * entry, FILE *f) {
1656        int i;
1657        struct singleLine * line;
1658    
1659        for (line = entry->lines; line; line = line->next) {
1660     log_message(f, "DBG: %s", line->indent);
1661     for (i = 0; i < line->numElements; i++) {
1662        /* Need to handle this, because we strip the quotes from
1663         * menuentry when read it. */
1664        if (line->type == LT_MENUENTRY && i == 1) {
1665     if(!isquote(*line->elements[i].item))
1666        log_message(f, "\'%s\'", line->elements[i].item);
1667     else
1668        log_message(f, "%s", line->elements[i].item);
1669     log_message(f, "%s", line->elements[i].indent);
1670    
1671     continue;
1672        }
1673        
1674        log_message(f, "%s%s",
1675        line->elements[i].item, line->elements[i].indent);
1676   }   }
1677     log_message(f, "\n");
1678      }      }
1679    }
1680    
1681      if (!strncmp(dev, "LABEL=", 6)) {  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1682   dev += 6;  {
1683        static int once;
1684        va_list argp, argq;
1685    
1686        va_start(argp, fmt);
1687    
1688        va_copy(argq, argp);
1689        if (!once) {
1690     log_time(NULL);
1691     log_message(NULL, "command line: %s\n", saved_command_line);
1692        }
1693        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1694        log_vmessage(NULL, fmt, argq);
1695    
1696   /* check which device has this label */      printEntry(entry, NULL);
1697   dev = get_spec_by_volume_label(dev, &i, &i);      va_end(argq);
1698   if (!dev) return 0;  
1699        if (!debug) {
1700     once = 1;
1701         va_end(argp);
1702     return;
1703      }      }
1704    
1705      if (*dev == '/') {      if (okay) {
1706   if (stat(dev, &sb))   va_end(argp);
1707      return 0;   return;
1708        }
1709    
1710        if (!once)
1711     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1712        once = 1;
1713        fprintf(stderr, "DBG: Image entry failed: ");
1714        vfprintf(stderr, fmt, argp);
1715        printEntry(entry, stderr);
1716        va_end(argp);
1717    }
1718    
1719    #define beginswith(s, c) ((s) && (s)[0] == (c))
1720    
1721    static int endswith(const char *s, char c)
1722    {
1723     int slen;
1724    
1725     if (!s || !s[0])
1726     return 0;
1727     slen = strlen(s) - 1;
1728    
1729     return s[slen] == c;
1730    }
1731    
1732    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1733      int skipRemoved, int flags) {
1734        struct singleLine * line;
1735        char * fullName;
1736        int i;
1737        char * dev;
1738        char * rootspec;
1739        char * rootdev;
1740    
1741        if (skipRemoved && entry->skip) {
1742     notSuitablePrintf(entry, 0, "marked to skip\n");
1743     return 0;
1744        }
1745    
1746        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1747        if (!line) {
1748     notSuitablePrintf(entry, 0, "no line found\n");
1749     return 0;
1750        }
1751        if (line->numElements < 2) {
1752     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1753        line->numElements);
1754     return 0;
1755        }
1756    
1757        if (flags & GRUBBY_BADIMAGE_OKAY) {
1758        notSuitablePrintf(entry, 1, "\n");
1759        return 1;
1760        }
1761    
1762        fullName = alloca(strlen(bootPrefix) +
1763          strlen(line->elements[1].item) + 1);
1764        rootspec = getRootSpecifier(line->elements[1].item);
1765        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1766        int hasslash = endswith(bootPrefix, '/') ||
1767         beginswith(line->elements[1].item + rootspec_offset, '/');
1768        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1769                line->elements[1].item + rootspec_offset);
1770        if (access(fullName, R_OK)) {
1771     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1772     return 0;
1773        }
1774        for (i = 2; i < line->numElements; i++)
1775     if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1776        if (i < line->numElements) {
1777     dev = line->elements[i].item + 5;
1778      } else {      } else {
1779   sb.st_rdev = strtol(dev, &end, 16);   /* look for a lilo style LT_ROOT line */
1780   if (*end) return 0;   line = getLineByType(LT_ROOT, entry->lines);
1781    
1782     if (line && line->numElements >= 2) {
1783        dev = line->elements[1].item;
1784     } else {
1785        /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1786         * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1787         */
1788        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1789    
1790                /* failed to find one */
1791                if (!line) {
1792     notSuitablePrintf(entry, 0, "no line found\n");
1793     return 0;
1794                }
1795    
1796        for (i = 1; i < line->numElements; i++)
1797            if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1798        if (i < line->numElements)
1799            dev = line->elements[i].item + 5;
1800        else {
1801     notSuitablePrintf(entry, 0, "no root= entry found\n");
1802     /* it failed too...  can't find root= */
1803            return 0;
1804                }
1805     }
1806        }
1807    
1808        dev = getpathbyspec(dev);
1809        if (!getpathbyspec(dev)) {
1810            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1811            return 0;
1812        } else
1813     dev = getpathbyspec(dev);
1814    
1815        rootdev = findDiskForRoot();
1816        if (!rootdev) {
1817            notSuitablePrintf(entry, 0, "can't find root device\n");
1818     return 0;
1819        }
1820    
1821        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1822            notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1823     getuuidbydev(rootdev), getuuidbydev(dev));
1824            free(rootdev);
1825            return 0;
1826        }
1827    
1828        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1829            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1830     getuuidbydev(rootdev), getuuidbydev(dev));
1831     free(rootdev);
1832            return 0;
1833      }      }
     stat("/", &sb2);  
1834    
1835      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1836        notSuitablePrintf(entry, 1, "\n");
1837    
1838      return 1;      return 1;
1839  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1877  struct singleEntry * findEntryByPath(str
1877   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1878   if (!entry) return NULL;   if (!entry) return NULL;
1879    
1880   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1881   if (!line) return NULL;   if (!line) return NULL;
1882    
1883   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1915  struct singleEntry * findEntryByPath(str
1915    
1916   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1917      prefix = "";      prefix = "";
1918      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1919      kernel += 6;      kernel += 6;
1920   }   }
1921    
1922   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1923      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1924    
1925        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1926    
1927      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1928                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1929          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
1930                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1931                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1932                      break;   else if (checkType & LT_KERNEL)
1933              }      ct = checkType | LT_KERNEL_EFI;
1934                 line = getLineByType(ct, line);
1935              /* have to check multiboot lines too */   if (!line)
1936              if (entry->multiboot) {      break;  /* not found in this entry */
1937                  while (line && line->type != LT_MBMODULE) line = line->next;  
1938                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
1939                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
1940                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
1941                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
1942                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
1943                          break;   kernel + strlen(prefix)))
1944                  }   break;
1945              }   }
1946     if(line->type == LT_MENUENTRY &&
1947     !strcmp(line->elements[1].item, kernel))
1948        break;
1949        }
1950    
1951      i++;      /* make sure this entry has a kernel identifier; this skips
1952         * non-Linux boot entries (could find netbsd etc, though, which is
1953         * unfortunate)
1954         */
1955        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1956     break; /* found 'im! */
1957   }   }
1958    
1959   if (index) *index = i;   if (index) *index = i;
1960      }      }
1961    
1962      if (!entry) return NULL;      return entry;
1963    }
1964    
1965      /* make sure this entry has a kernel identifier; this skips non-Linux  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
1966         boot entries (could find netbsd etc, though, which is unfortunate) */        int * index) {
1967      line = entry->lines;      struct singleEntry * entry;
1968      while (line && line->type != LT_KERNEL) line = line->next;      struct singleLine * line;
1969      if (!line) {      int i;
1970   if (!index) index = &i;      char * newtitle;
1971   (*index)++;  
1972   return findEntryByPath(config, kernel, prefix, index);      for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
1973     if (index && i < *index)
1974        continue;
1975     line = getLineByType(LT_TITLE, entry->lines);
1976     if (!line)
1977        line = getLineByType(LT_MENUENTRY, entry->lines);
1978     if (!line)
1979        continue;
1980     newtitle = grub2ExtractTitle(line);
1981     if (!newtitle)
1982        continue;
1983     if (!strcmp(title, newtitle))
1984        break;
1985      }      }
1986    
1987        if (!entry)
1988     return NULL;
1989    
1990        if (index)
1991     *index = i;
1992      return entry;      return entry;
1993  }  }
1994    
# Line 1147  struct singleEntry * findTemplate(struct Line 2014  struct singleEntry * findTemplate(struct
2014      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2015      int index;      int index;
2016    
2017      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2018     if (cfg->cfi->getEnv) {
2019        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2020        if (defTitle) {
2021     int index = 0;
2022     entry = findEntryByTitle(cfg, defTitle, &index);
2023        }
2024     }
2025        } else if (cfg->defaultImage > -1) {
2026   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2027   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2028      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1200  void markRemovedImage(struct grubConfig Line 2075  void markRemovedImage(struct grubConfig
2075        const char * prefix) {        const char * prefix) {
2076      struct singleEntry * entry;      struct singleEntry * entry;
2077    
2078      if (!image) return;      if (!image)
2079     return;
2080    
2081        /* check and see if we're removing the default image */
2082        if (isdigit(*image)) {
2083     entry = findEntryByPath(cfg, image, prefix, NULL);
2084     if(entry)
2085        entry->skip = 1;
2086     return;
2087        }
2088    
2089      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2090   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 2092  void markRemovedImage(struct grubConfig
2092    
2093  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2094       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2095       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2096      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2097      int i, j;      int i, j;
2098    
2099      if (newIsDefault) {      if (newIsDefault) {
2100   config->defaultImage = 0;   config->defaultImage = 0;
2101   return;   return;
2102        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2103     if (findEntryByIndex(config, index))
2104        config->defaultImage = index;
2105     else
2106        config->defaultImage = -1;
2107     return;
2108      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2109   i = 0;   i = 0;
2110   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 2117  void setDefaultImage(struct grubConfig *
2117    
2118      /* 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
2119         changes */         changes */
2120      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2121     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2122        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2123        return;        return;
2124    
# Line 1286  void displayEntry(struct singleEntry * e Line 2177  void displayEntry(struct singleEntry * e
2177      char * root = NULL;      char * root = NULL;
2178      int i;      int i;
2179    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2180      printf("index=%d\n", index);      printf("index=%d\n", index);
2181    
2182      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
2183        if (!line) {
2184            printf("non linux entry\n");
2185            return;
2186        }
2187    
2188        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2189     printf("kernel=%s\n", line->elements[1].item);
2190        else
2191     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2192    
2193      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2194   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2205  void displayEntry(struct singleEntry * e
2205   }   }
2206   printf("\"\n");   printf("\"\n");
2207      } else {      } else {
2208   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2209   if (line) {   if (line) {
2210      char * s;      char * s;
2211    
# Line 1334  void displayEntry(struct singleEntry * e Line 2229  void displayEntry(struct singleEntry * e
2229      }      }
2230    
2231      if (!root) {      if (!root) {
2232   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2233   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2234      root=line->elements[1].item;      root=line->elements[1].item;
2235      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2244  void displayEntry(struct singleEntry * e
2244   printf("root=%s\n", s);   printf("root=%s\n", s);
2245      }      }
2246    
2247      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2248    
2249      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2250   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2251        printf("initrd=");
2252     else
2253        printf("initrd=%s", prefix);
2254    
2255   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2256      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2257   printf("\n");   printf("\n");
2258      }      }
2259    
2260        line = getLineByType(LT_TITLE, entry->lines);
2261        if (line) {
2262     printf("title=%s\n", line->elements[1].item);
2263        } else {
2264     char * title;
2265     line = getLineByType(LT_MENUENTRY, entry->lines);
2266     title = grub2ExtractTitle(line);
2267     if (title)
2268        printf("title=%s\n", title);
2269        }
2270    }
2271    
2272    int isSuseSystem(void) {
2273        const char * path;
2274        const static char default_path[] = "/etc/SuSE-release";
2275    
2276        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2277     path = default_path;
2278    
2279        if (!access(path, R_OK))
2280     return 1;
2281        return 0;
2282    }
2283    
2284    int isSuseGrubConf(const char * path) {
2285        FILE * grubConf;
2286        char * line = NULL;
2287        size_t len = 0, res = 0;
2288    
2289        grubConf = fopen(path, "r");
2290        if (!grubConf) {
2291            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2292     return 0;
2293        }
2294    
2295        while ((res = getline(&line, &len, grubConf)) != -1) {
2296     if (!strncmp(line, "setup", 5)) {
2297        fclose(grubConf);
2298        free(line);
2299        return 1;
2300     }
2301        }
2302    
2303        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2304          path);
2305    
2306        fclose(grubConf);
2307        free(line);
2308        return 0;
2309    }
2310    
2311    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2312        FILE * grubConf;
2313        char * line = NULL;
2314        size_t res = 0, len = 0;
2315    
2316        if (!path) return 1;
2317        if (!lbaPtr) return 1;
2318    
2319        grubConf = fopen(path, "r");
2320        if (!grubConf) return 1;
2321    
2322        while ((res = getline(&line, &len, grubConf)) != -1) {
2323     if (line[res - 1] == '\n')
2324        line[res - 1] = '\0';
2325     else if (len > res)
2326        line[res] = '\0';
2327     else {
2328        line = realloc(line, res + 1);
2329        line[res] = '\0';
2330     }
2331    
2332     if (!strncmp(line, "setup", 5)) {
2333        if (strstr(line, "--force-lba")) {
2334            *lbaPtr = 1;
2335        } else {
2336            *lbaPtr = 0;
2337        }
2338        dbgPrintf("lba: %i\n", *lbaPtr);
2339        break;
2340     }
2341        }
2342    
2343        free(line);
2344        fclose(grubConf);
2345        return 0;
2346    }
2347    
2348    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2349        FILE * grubConf;
2350        char * line = NULL;
2351        size_t res = 0, len = 0;
2352        char * lastParamPtr = NULL;
2353        char * secLastParamPtr = NULL;
2354        char installDeviceNumber = '\0';
2355        char * bounds = NULL;
2356    
2357        if (!path) return 1;
2358        if (!devicePtr) return 1;
2359    
2360        grubConf = fopen(path, "r");
2361        if (!grubConf) return 1;
2362    
2363        while ((res = getline(&line, &len, grubConf)) != -1) {
2364     if (strncmp(line, "setup", 5))
2365        continue;
2366    
2367     if (line[res - 1] == '\n')
2368        line[res - 1] = '\0';
2369     else if (len > res)
2370        line[res] = '\0';
2371     else {
2372        line = realloc(line, res + 1);
2373        line[res] = '\0';
2374     }
2375    
2376     lastParamPtr = bounds = line + res;
2377    
2378     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2379     while (!isspace(*lastParamPtr))
2380        lastParamPtr--;
2381     lastParamPtr++;
2382    
2383     secLastParamPtr = lastParamPtr - 2;
2384     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2385    
2386     if (lastParamPtr + 3 > bounds) {
2387        dbgPrintf("lastParamPtr going over boundary");
2388        fclose(grubConf);
2389        free(line);
2390        return 1;
2391     }
2392     if (!strncmp(lastParamPtr, "(hd", 3))
2393        lastParamPtr += 3;
2394     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2395    
2396     /*
2397     * Second last parameter will decide wether last parameter is
2398     * an IMAGE_DEVICE or INSTALL_DEVICE
2399     */
2400     while (!isspace(*secLastParamPtr))
2401        secLastParamPtr--;
2402     secLastParamPtr++;
2403    
2404     if (secLastParamPtr + 3 > bounds) {
2405        dbgPrintf("secLastParamPtr going over boundary");
2406        fclose(grubConf);
2407        free(line);
2408        return 1;
2409     }
2410     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2411     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2412        secLastParamPtr += 3;
2413        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2414        installDeviceNumber = *secLastParamPtr;
2415     } else {
2416        installDeviceNumber = *lastParamPtr;
2417     }
2418    
2419     *devicePtr = malloc(6);
2420     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2421     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2422     fclose(grubConf);
2423     free(line);
2424     return 0;
2425        }
2426    
2427        free(line);
2428        fclose(grubConf);
2429        return 1;
2430    }
2431    
2432    int grubGetBootFromDeviceMap(const char * device,
2433         char ** bootPtr) {
2434        FILE * deviceMap;
2435        char * line = NULL;
2436        size_t res = 0, len = 0;
2437        char * devicePtr;
2438        char * bounds = NULL;
2439        const char * path;
2440        const static char default_path[] = "/boot/grub/device.map";
2441    
2442        if (!device) return 1;
2443        if (!bootPtr) return 1;
2444    
2445        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2446     path = default_path;
2447    
2448        dbgPrintf("opening grub device.map file from: %s\n", path);
2449        deviceMap = fopen(path, "r");
2450        if (!deviceMap)
2451     return 1;
2452    
2453        while ((res = getline(&line, &len, deviceMap)) != -1) {
2454            if (!strncmp(line, "#", 1))
2455        continue;
2456    
2457     if (line[res - 1] == '\n')
2458        line[res - 1] = '\0';
2459     else if (len > res)
2460        line[res] = '\0';
2461     else {
2462        line = realloc(line, res + 1);
2463        line[res] = '\0';
2464     }
2465    
2466     devicePtr = line;
2467     bounds = line + res;
2468    
2469     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2470        devicePtr++;
2471     dbgPrintf("device: %s\n", devicePtr);
2472    
2473     if (!strncmp(devicePtr, device, strlen(device))) {
2474        devicePtr += strlen(device);
2475        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2476            devicePtr++;
2477    
2478        *bootPtr = strdup(devicePtr);
2479        break;
2480     }
2481        }
2482    
2483        free(line);
2484        fclose(deviceMap);
2485        return 0;
2486    }
2487    
2488    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2489        char * grubDevice;
2490    
2491        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2492     dbgPrintf("error looking for grub installation device\n");
2493        else
2494     dbgPrintf("grubby installation device: %s\n", grubDevice);
2495    
2496        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2497     dbgPrintf("error looking for grub boot device\n");
2498        else
2499     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2500    
2501        free(grubDevice);
2502        return 0;
2503    }
2504    
2505    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2506        /*
2507         * This SuSE grub configuration file at this location is not your average
2508         * grub configuration file, but instead the grub commands used to setup
2509         * grub on that system.
2510         */
2511        const char * path;
2512        const static char default_path[] = "/etc/grub.conf";
2513    
2514        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2515     path = default_path;
2516    
2517        if (!isSuseGrubConf(path)) return 1;
2518    
2519        if (lbaPtr) {
2520            *lbaPtr = 0;
2521            if (suseGrubConfGetLba(path, lbaPtr))
2522                return 1;
2523        }
2524    
2525        if (bootPtr) {
2526            *bootPtr = NULL;
2527            suseGrubConfGetBoot(path, bootPtr);
2528        }
2529    
2530        return 0;
2531  }  }
2532    
2533  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2537  int parseSysconfigGrub(int * lbaPtr, cha
2537      char * start;      char * start;
2538      char * param;      char * param;
2539    
2540      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2541      if (!in) return 1;      if (!in) return 1;
2542    
2543      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2578  int parseSysconfigGrub(int * lbaPtr, cha
2578  }  }
2579    
2580  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2581      char * boot;      char * boot = NULL;
2582      int lba;      int lba;
2583    
2584      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2585   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2586   if (boot) printf("boot=%s\n", boot);      free(boot);
2587        return;
2588     }
2589        } else {
2590            if (parseSysconfigGrub(&lba, &boot)) {
2591        free(boot);
2592        return;
2593     }
2594        }
2595    
2596        if (lba) printf("lba\n");
2597        if (boot) {
2598     printf("boot=%s\n", boot);
2599     free(boot);
2600      }      }
2601  }  }
2602    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2612  int displayInfo(struct grubConfig * conf
2612   return 1;   return 1;
2613      }      }
2614    
2615      /* 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
2616         be a better way */         be a better way */
2617      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2618   dumpSysconfigGrub();   dumpSysconfigGrub();
2619      } else {      } else {
2620   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2621   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2622      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2623   }   }
2624    
2625   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2626   if (line) printf("lba\n");   if (line) printf("lba\n");
2627      }      }
2628    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2637  int displayInfo(struct grubConfig * conf
2637      return 0;      return 0;
2638  }  }
2639    
2640    struct singleLine * addLineTmpl(struct singleEntry * entry,
2641     struct singleLine * tmplLine,
2642     struct singleLine * prevLine,
2643     const char * val,
2644     struct configFileInfo * cfi)
2645    {
2646        struct singleLine * newLine = lineDup(tmplLine);
2647    
2648        if (isEfi && cfi == &grub2ConfigType) {
2649     enum lineType_e old = newLine->type;
2650     newLine->type = preferredLineType(newLine->type, cfi);
2651     if (old != newLine->type)
2652        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2653        }
2654    
2655        if (val) {
2656     /* override the inherited value with our own.
2657     * This is a little weak because it only applies to elements[1]
2658     */
2659     if (newLine->numElements > 1)
2660        removeElement(newLine, 1);
2661     insertElement(newLine, val, 1, cfi);
2662    
2663     /* but try to keep the rootspec from the template... sigh */
2664     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2665        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2666        if (rootspec != NULL) {
2667     free(newLine->elements[1].item);
2668     newLine->elements[1].item =
2669        sdupprintf("%s%s", rootspec, val);
2670        }
2671     }
2672        }
2673    
2674        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2675          newLine->elements[0].item : "");
2676    
2677        if (!entry->lines) {
2678     /* first one on the list */
2679     entry->lines = newLine;
2680        } else if (prevLine) {
2681     /* add after prevLine */
2682     newLine->next = prevLine->next;
2683     prevLine->next = newLine;
2684        }
2685    
2686        return newLine;
2687    }
2688    
2689  /* val may be NULL */  /* val may be NULL */
2690  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2691       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2692       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2693       char * val) {       const char * val) {
2694      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2695      int i;      struct keywordTypes * kw;
2696        struct singleLine tmpl;
2697    
2698      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2699   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2700      if (type != LT_TITLE || !cfi->titleBracketed)       */
2701          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2702     /* we're doing a bracketed title (zipl) */
2703     tmpl.type = type;
2704     tmpl.numElements = 1;
2705     tmpl.elements = alloca(sizeof(*tmpl.elements));
2706     tmpl.elements[0].item = alloca(strlen(val)+3);
2707     sprintf(tmpl.elements[0].item, "[%s]", val);
2708     tmpl.elements[0].indent = "";
2709     val = NULL;
2710        } else if (type == LT_MENUENTRY) {
2711     char *lineend = "--class gnu-linux --class gnu --class os {";
2712     if (!val) {
2713        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2714        abort();
2715     }
2716     kw = getKeywordByType(type, cfi);
2717     if (!kw) {
2718        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2719        abort();
2720     }
2721     tmpl.indent = "";
2722     tmpl.type = type;
2723     tmpl.numElements = 3;
2724     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2725     tmpl.elements[0].item = kw->key;
2726     tmpl.elements[0].indent = alloca(2);
2727     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2728     tmpl.elements[1].item = (char *)val;
2729     tmpl.elements[1].indent = alloca(2);
2730     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2731     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2732     strcpy(tmpl.elements[2].item, lineend);
2733     tmpl.elements[2].indent = "";
2734        } else {
2735     kw = getKeywordByType(type, cfi);
2736     if (!kw) {
2737        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2738        abort();
2739     }
2740     tmpl.type = type;
2741     tmpl.numElements = val ? 2 : 1;
2742     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2743     tmpl.elements[0].item = kw->key;
2744     tmpl.elements[0].indent = alloca(2);
2745     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2746     if (val) {
2747        tmpl.elements[1].item = (char *)val;
2748        tmpl.elements[1].indent = "";
2749     }
2750        }
2751    
2752      /* 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
2753         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2754         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
2755         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2756         differently from the rest) */         differently from the rest) */
2757      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2758   line = entry->lines;   if (line->numElements) prev = line;
2759   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2760   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;  
2761      }      }
2762    
2763      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2764          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2765          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2766          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2767          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2768          line->elements[0].indent = malloc(2);   else
2769          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2770          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2771             if (menuEntry)
2772          if (val) {      tmpl.indent = "\t";
2773              line->elements[1].item = val;   else if (prev == entry->lines)
2774              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2775          }   else
2776      } 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("");  
2777      }      }
2778    
2779      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2780  }  }
2781    
2782  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2801  void removeLine(struct singleEntry * ent
2801      free(line);      free(line);
2802  }  }
2803    
2804    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2805    {
2806        struct singleLine newLine = {
2807     .indent = tmplLine->indent,
2808     .type = tmplLine->type,
2809     .next = tmplLine->next,
2810        };
2811        int firstQuotedItem = -1;
2812        int quoteLen = 0;
2813        int j;
2814        int element = 0;
2815        char *c;
2816    
2817        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2818        strcpy(c, tmplLine->elements[0].item);
2819        insertElement(&newLine, c, element++, cfi);
2820        free(c);
2821        c = NULL;
2822    
2823        for (j = 1; j < tmplLine->numElements; j++) {
2824     if (firstQuotedItem == -1) {
2825        quoteLen += strlen(tmplLine->elements[j].item);
2826        
2827        if (isquote(tmplLine->elements[j].item[0])) {
2828     firstQuotedItem = j;
2829            quoteLen += strlen(tmplLine->elements[j].indent);
2830        } else {
2831     c = malloc(quoteLen + 1);
2832     strcpy(c, tmplLine->elements[j].item);
2833     insertElement(&newLine, c, element++, cfi);
2834     free(c);
2835     quoteLen = 0;
2836        }
2837     } else {
2838        int itemlen = strlen(tmplLine->elements[j].item);
2839        quoteLen += itemlen;
2840        quoteLen += strlen(tmplLine->elements[j].indent);
2841        
2842        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2843     c = malloc(quoteLen + 1);
2844     c[0] = '\0';
2845     for (int i = firstQuotedItem; i < j+1; i++) {
2846        strcat(c, tmplLine->elements[i].item);
2847        strcat(c, tmplLine->elements[i].indent);
2848     }
2849     insertElement(&newLine, c, element++, cfi);
2850     free(c);
2851    
2852     firstQuotedItem = -1;
2853     quoteLen = 0;
2854        }
2855     }
2856        }
2857        while (tmplLine->numElements)
2858     removeElement(tmplLine, 0);
2859        if (tmplLine->elements)
2860     free(tmplLine->elements);
2861    
2862        tmplLine->numElements = newLine.numElements;
2863        tmplLine->elements = newLine.elements;
2864    }
2865    
2866    static void insertElement(struct singleLine * line,
2867      const char * item, int insertHere,
2868      struct configFileInfo * cfi)
2869    {
2870        struct keywordTypes * kw;
2871        char indent[2] = "";
2872    
2873        /* sanity check */
2874        if (insertHere > line->numElements) {
2875     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2876      insertHere, line->numElements);
2877     insertHere = line->numElements;
2878        }
2879    
2880        line->elements = realloc(line->elements, (line->numElements + 1) *
2881         sizeof(*line->elements));
2882        memmove(&line->elements[insertHere+1],
2883        &line->elements[insertHere],
2884        (line->numElements - insertHere) *
2885        sizeof(*line->elements));
2886        line->elements[insertHere].item = strdup(item);
2887    
2888        kw = getKeywordByType(line->type, cfi);
2889    
2890        if (line->numElements == 0) {
2891     indent[0] = '\0';
2892        } else if (insertHere == 0) {
2893     indent[0] = kw->nextChar;
2894        } else if (kw->separatorChar != '\0') {
2895     indent[0] = kw->separatorChar;
2896        } else {
2897     indent[0] = ' ';
2898        }
2899    
2900        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2901     /* move the end-of-line forward */
2902     line->elements[insertHere].indent =
2903        line->elements[insertHere-1].indent;
2904     line->elements[insertHere-1].indent = strdup(indent);
2905        } else {
2906     line->elements[insertHere].indent = strdup(indent);
2907        }
2908    
2909        line->numElements++;
2910    
2911        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2912          line->elements[0].item,
2913          line->elements[insertHere].item,
2914          line->elements[insertHere].indent,
2915          insertHere);
2916    }
2917    
2918    static void removeElement(struct singleLine * line, int removeHere) {
2919        int i;
2920    
2921        /* sanity check */
2922        if (removeHere >= line->numElements) return;
2923    
2924        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2925          removeHere, line->elements[removeHere].item);
2926    
2927        free(line->elements[removeHere].item);
2928    
2929        if (removeHere > 1) {
2930     /* previous argument gets this argument's post-indentation */
2931     free(line->elements[removeHere-1].indent);
2932     line->elements[removeHere-1].indent =
2933        line->elements[removeHere].indent;
2934        } else {
2935     free(line->elements[removeHere].indent);
2936        }
2937    
2938        /* now collapse the array, but don't bother to realloc smaller */
2939        for (i = removeHere; i < line->numElements - 1; i++)
2940     line->elements[i] = line->elements[i + 1];
2941    
2942        line->numElements--;
2943    }
2944    
2945  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2946      char * first, * second;      char * first, * second;
2947      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2964  int updateActualImage(struct grubConfig
2964      struct singleEntry * entry;      struct singleEntry * entry;
2965      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2966      int index = 0;      int index = 0;
2967      int i, j, k;      int i, k;
2968      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2969      const char ** arg;      const char ** arg;
2970      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2971      int firstElement;      int firstElement;
2972      int *usedElements, *usedArgs;      int *usedElements;
2973        int doreplace;
2974    
2975      if (!image) return 0;      if (!image) return 0;
2976    
# Line 1609  int updateActualImage(struct grubConfig Line 2997  int updateActualImage(struct grubConfig
2997   }   }
2998      }      }
2999    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
3000    
3001      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
3002   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
3003    
3004      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3005   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
3006    
3007      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
3008    
3009      k = 0;   if (multibootArgs && !entry->multiboot)
3010      for (arg = newArgs; *arg; arg++)      continue;
3011          k++;  
3012      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
3013     * LT_KERNELARGS, use that.  Otherwise use
3014     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
3015     */
3016     if (useKernelArgs) {
3017        line = getLineByType(LT_KERNELARGS, entry->lines);
3018        if (!line) {
3019     /* no LT_KERNELARGS, need to add it */
3020     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
3021           cfg->secondaryIndent, NULL);
3022        }
3023        firstElement = 1;
3024    
3025      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
3026   index++;      line = getLineByType(LT_HYPER, entry->lines);
3027        if (!line) {
3028     /* a multiboot entry without LT_HYPER? */
3029     continue;
3030        }
3031        firstElement = 2;
3032    
3033   line = entry->lines;   } else {
3034   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
3035   if (!line) continue;      if (!line) {
3036   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3037     continue;
3038          if (entry->multiboot && !multibootArgs) {      }
3039              /* 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;  
3040   }   }
3041    
3042   if (!line && useKernelArgs) {   /* handle the elilo case which does:
3043      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
3044      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
3045     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
3046        /* this is a multiboot entry, make sure there's
3047         * -- on the args line
3048         */
3049        for (i = firstElement; i < line->numElements; i++) {
3050     if (!strcmp(line->elements[i].item, "--"))
3051        break;
3052        }
3053        if (i == line->numElements) {
3054     /* assume all existing args are kernel args,
3055     * prepend -- to make it official
3056     */
3057     insertElement(line, "--", firstElement, cfg->cfi);
3058     i = firstElement;
3059        }
3060        if (!multibootArgs) {
3061     /* kernel args start after the -- */
3062     firstElement = i + 1;
3063        }
3064     } else if (cfg->cfi->mbConcatArgs) {
3065        /* this is a non-multiboot entry, remove hyper args */
3066        for (i = firstElement; i < line->numElements; i++) {
3067     if (!strcmp(line->elements[i].item, "--"))
3068        break;
3069        }
3070        if (i < line->numElements) {
3071     /* remove args up to -- */
3072     while (strcmp(line->elements[firstElement].item, "--"))
3073        removeElement(line, firstElement);
3074     /* remove -- */
3075     removeElement(line, firstElement);
3076        }
3077   }   }
3078    
3079          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
3080    
3081          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
3082   for (arg = newArgs; *arg; arg++) {  
3083              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
3084      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
3085     if (multibootArgs && cfg->cfi->mbConcatArgs &&
3086        !strcmp(line->elements[i].item, "--"))
3087     {
3088        /* reached the end of hyper args, insert here */
3089        doreplace = 0;
3090        break;  
3091     }
3092                  if (usedElements[i])                  if (usedElements[i])
3093                      continue;                      continue;
3094   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3095                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3096      break;      break;
3097                  }                  }
3098              }              }
     chptr = strchr(*arg, '=');  
3099    
3100      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
3101   /* replace */   /* direct replacement */
3102   free(line->elements[i].item);   free(line->elements[i].item);
3103   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("");  
  }  
3104    
3105   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
3106   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
3107      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
3108   /* append */   if (rootLine) {
3109   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
3110   (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(" ");  
3111   } else {   } else {
3112      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
3113         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
3114   }   }
3115        }
3116    
3117   line->numElements++;      else {
3118     /* insert/append */
3119     insertElement(line, *arg, i, cfg->cfi);
3120     usedElements = realloc(usedElements, line->numElements *
3121           sizeof(*usedElements));
3122     memmove(&usedElements[i + 1], &usedElements[i],
3123     line->numElements - i - 1);
3124     usedElements[i] = 1;
3125    
3126   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
3127     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
3128     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
3129   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
3130      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
3131      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
3132   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
3133   }   }
3134      }      }
             k++;  
3135   }   }
3136    
3137          free(usedElements);          free(usedElements);
3138    
  /* 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? */  
3139   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
3140      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3141   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3142        !strcmp(line->elements[i].item, "--"))
3143        /* reached the end of hyper args, stop here */
3144        break;
3145     if (!argMatch(line->elements[i].item, *arg)) {
3146        removeElement(line, i);
3147      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;  
3148   }   }
3149        }
3150   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3151        if (useRoot && !strncmp(*arg, "root=", 5)) {
3152   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3153      line->elements[j - 1] = line->elements[j];   if (rootLine)
3154        removeLine(entry, rootLine);
  line->numElements--;  
3155      }      }
3156   }   }
3157    
# Line 1760  int updateActualImage(struct grubConfig Line 3162  int updateActualImage(struct grubConfig
3162   }   }
3163      }      }
3164    
     free(usedArgs);  
3165      free(newArgs);      free(newArgs);
3166      free(oldArgs);      free(oldArgs);
3167    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3187  int updateImage(struct grubConfig * cfg,
3187      return rc;      return rc;
3188  }  }
3189    
3190    int updateInitrd(struct grubConfig * cfg, const char * image,
3191                     const char * prefix, const char * initrd) {
3192        struct singleEntry * entry;
3193        struct singleLine * line, * kernelLine, *endLine = NULL;
3194        int index = 0;
3195    
3196        if (!image) return 0;
3197    
3198        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3199            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3200            if (!kernelLine) continue;
3201    
3202            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3203            if (line)
3204                removeLine(entry, line);
3205            if (prefix) {
3206                int prefixLen = strlen(prefix);
3207                if (!strncmp(initrd, prefix, prefixLen))
3208                    initrd += prefixLen;
3209            }
3210     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3211     if (endLine)
3212        removeLine(entry, endLine);
3213            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3214     kernelLine->indent, initrd);
3215            if (!line)
3216        return 1;
3217     if (endLine) {
3218        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3219                if (!line)
3220     return 1;
3221     }
3222    
3223            break;
3224        }
3225    
3226        return 0;
3227    }
3228    
3229  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3230      int fd;      int fd;
3231      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3249  int checkDeviceBootloader(const char * d
3249      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3250   return 0;   return 0;
3251    
3252      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3253   offset = boot[2] + 2;   offset = boot[2] + 2;
3254      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3255   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3256      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3257   offset = boot[1] + 2;        offset = boot[1] + 2;
3258            /*
3259     * it looks like grub, when copying stage1 into the mbr, patches stage1
3260     * right after the JMP location, replacing other instructions such as
3261     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3262     * different bytes.
3263     */
3264          if ((bootSect[offset + 1] == NOOP_OPCODE)
3265      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3266     offset = offset + 3;
3267          }
3268      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3269   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3270      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3406  int checkForLilo(struct grubConfig * con
3406      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3407  }  }
3408    
3409    int checkForGrub2(struct grubConfig * config) {
3410        if (!access("/etc/grub.d/", R_OK))
3411     return 2;
3412    
3413        return 1;
3414    }
3415    
3416  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3417      int fd;      int fd;
3418      unsigned char bootSect[512];      unsigned char bootSect[512];
3419      char * boot;      char * boot;
3420        int onSuse = isSuseSystem();
3421    
3422      if (parseSysconfigGrub(NULL, &boot))  
3423   return 0;      if (onSuse) {
3424     if (parseSuseGrubConf(NULL, &boot))
3425        return 0;
3426        } else {
3427     if (parseSysconfigGrub(NULL, &boot))
3428        return 0;
3429        }
3430    
3431      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3432      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3440  int checkForGrub(struct grubConfig * con
3440      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3441   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3442   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3443     close(fd);
3444   return 1;   return 1;
3445      }      }
3446      close(fd);      close(fd);
3447    
3448        /* The more elaborate checks do not work on SuSE. The checks done
3449         * seem to be reasonble (at least for now), so just return success
3450         */
3451        if (onSuse)
3452     return 2;
3453    
3454      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3455  }  }
3456    
3457    int checkForExtLinux(struct grubConfig * config) {
3458        int fd;
3459        unsigned char bootSect[512];
3460        char * boot;
3461        char executable[] = "/boot/extlinux/extlinux";
3462    
3463        printf("entered: checkForExtLinux()\n");
3464    
3465        if (parseSysconfigGrub(NULL, &boot))
3466     return 0;
3467    
3468        /* assume grub is not installed -- not an error condition */
3469        if (!boot)
3470     return 0;
3471    
3472        fd = open(executable, O_RDONLY);
3473        if (fd < 0)
3474     /* this doesn't exist if grub hasn't been installed */
3475     return 0;
3476    
3477        if (read(fd, bootSect, 512) != 512) {
3478     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3479     executable, strerror(errno));
3480     return 1;
3481        }
3482        close(fd);
3483    
3484        return checkDeviceBootloader(boot, bootSect);
3485    }
3486    
3487    int checkForYaboot(struct grubConfig * config) {
3488        /*
3489         * This is a simplistic check that we consider good enough for own puporses
3490         *
3491         * If we were to properly check if yaboot is *installed* we'd need to:
3492         * 1) get the system boot device (LT_BOOT)
3493         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3494         *    the content on the boot device
3495         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3496         * 4) check again if binary and boot device contents match
3497         */
3498        if (!access("/etc/yaboot.conf", R_OK))
3499     return 2;
3500    
3501        return 1;
3502    }
3503    
3504    int checkForElilo(struct grubConfig * config) {
3505        if (!access("/etc/elilo.conf", R_OK))
3506     return 2;
3507    
3508        return 1;
3509    }
3510    
3511  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3512      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3513    
# Line 1994  static char * getRootSpecifier(char * st Line 3519  static char * getRootSpecifier(char * st
3519      return rootspec;      return rootspec;
3520  }  }
3521    
3522    static char * getInitrdVal(struct grubConfig * config,
3523       const char * prefix, struct singleLine *tmplLine,
3524       const char * newKernelInitrd,
3525       const char ** extraInitrds, int extraInitrdCount)
3526    {
3527        char *initrdVal, *end;
3528        int i;
3529        size_t totalSize;
3530        size_t prefixLen;
3531        char separatorChar;
3532    
3533        prefixLen = strlen(prefix);
3534        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3535    
3536        for (i = 0; i < extraInitrdCount; i++) {
3537     totalSize += sizeof(separatorChar);
3538     totalSize += strlen(extraInitrds[i]) - prefixLen;
3539        }
3540    
3541        initrdVal = end = malloc(totalSize);
3542    
3543        end = stpcpy (end, newKernelInitrd + prefixLen);
3544    
3545        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3546        for (i = 0; i < extraInitrdCount; i++) {
3547     const char *extraInitrd;
3548     int j;
3549    
3550     extraInitrd = extraInitrds[i] + prefixLen;
3551     /* Don't add entries that are already there */
3552     if (tmplLine != NULL) {
3553        for (j = 2; j < tmplLine->numElements; j++)
3554     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3555        break;
3556    
3557        if (j != tmplLine->numElements)
3558     continue;
3559     }
3560    
3561     *end++ = separatorChar;
3562     end = stpcpy(end, extraInitrd);
3563        }
3564    
3565        return initrdVal;
3566    }
3567    
3568  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3569           const char * prefix,           const char * prefix,
3570   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3571   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3572                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3573                     const char * newMBKernel, const char * newMBKernelArgs) {
3574      struct singleEntry * new;      struct singleEntry * new;
3575      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3576      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3577      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3578    
3579      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3580    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3604  int addNewKernel(struct grubConfig * con
3604      config->entries = new;      config->entries = new;
3605    
3606      /* copy/update from the template */      /* copy/update from the template */
3607      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3608        if (newKernelInitrd)
3609     needs |= NEED_INITRD;
3610      if (newMBKernel) {      if (newMBKernel) {
3611          needs |= KERNEL_MB;          needs |= NEED_MB;
3612          new->multiboot = 1;          new->multiboot = 1;
3613      }      }
3614    
3615      if (template) {      if (template) {
3616   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3617      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3618      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3619   indent = tmplLine->indent;   {
3620        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3621    
3622      /* skip comments */      /* skip comments */
3623      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3624      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3625      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3626    
3627      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3628      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3629        /* it's not a multiboot template and this is the kernel
3630              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3631                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3632                  struct singleLine *l;       */
3633                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3634     /* insert the hypervisor first */
3635                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3636                                    config->secondaryIndent,    tmplLine->indent,
3637                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3638                     /* set up for adding the kernel line */
3639                  tmplLine = lastLine;   free(tmplLine->indent);
3640                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3641                      new->lines = l;   needs &= ~NEED_MB;
3642                  } else {      }
3643                      newLine->next = l;      if (needs & NEED_KERNEL) {
3644                      newLine = l;   /* use addLineTmpl to preserve line elements,
3645                  }   * otherwise we could just call addLine.  Unfortunately
3646                  continue;   * this means making some changes to the template
3647              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3648                         template->multiboot && !new->multiboot) {   * change below.
3649                  continue; /* don't need multiboot kernel here */   */
3650              }   struct keywordTypes * mbm_kw =
3651        getKeywordByType(LT_MBMODULE, config->cfi);
3652      if (!new->lines) {   if (mbm_kw) {
3653   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3654   new->lines = newLine;      free(tmplLine->elements[0].item);
3655      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3656   newLine->next = malloc(sizeof(*newLine));   }
3657   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3658      }        newKernelPath + strlen(prefix), config->cfi);
3659     needs &= ~NEED_KERNEL;
3660        }
3661        if (needs & NEED_MB) { /* !mbHyperFirst */
3662     newLine = addLine(new, config->cfi, LT_HYPER,
3663      config->secondaryIndent,
3664      newMBKernel + strlen(prefix));
3665     needs &= ~NEED_MB;
3666        }
3667     } else if (needs & NEED_KERNEL) {
3668        newLine = addLineTmpl(new, tmplLine, newLine,
3669      newKernelPath + strlen(prefix), config->cfi);
3670        needs &= ~NEED_KERNEL;
3671     }
3672    
3673        } else if (tmplLine->type == LT_HYPER &&
3674           tmplLine->numElements >= 2) {
3675     if (needs & NEED_MB) {
3676        newLine = addLineTmpl(new, tmplLine, newLine,
3677      newMBKernel + strlen(prefix), config->cfi);
3678        needs &= ~NEED_MB;
3679     }
3680    
3681      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3682      newLine->next = NULL;         tmplLine->numElements >= 2) {
3683      newLine->type = tmplLine->type;   if (new->multiboot) {
3684      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3685      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3686      newLine->numElements);        newKernelPath +
3687      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3688   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3689   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3690   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3691      }   char *initrdVal;
3692     initrdVal = getInitrdVal(config, prefix, tmplLine,
3693              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3694      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3695                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3696                  if (!template->multiboot) {        initrdVal, config->cfi);
3697                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3698                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3699                  } else {      }
3700                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3701                      repl = newMBKernel;      /* template is multi but new is not,
3702                  }       * insert the kernel in the first module slot
3703                  if (new->multiboot && !template->multiboot) {       */
3704                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3705                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3706                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3707                  }   strdup(getKeywordByType(tmplLine->type,
3708   free(newLine->elements[1].item);   config->cfi)->key);
3709                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3710                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3711                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3712                                                             rootspec,      needs &= ~NEED_KERNEL;
3713                                                             repl +   } else if (needs & NEED_INITRD) {
3714                                                             strlen(prefix));      char *initrdVal;
3715                  } else {      /* template is multi but new is not,
3716                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3717                                                         strlen(prefix));       */
3718                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3719              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3720                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3721                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3722                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3723                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3724                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3725                      newLine->type = LT_KERNEL;      free(initrdVal);
3726                  }      needs &= ~NEED_INITRD;
3727   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));  
                 }  
     } else if (tmplLine->type == LT_INITRD &&  
     tmplLine->numElements >= 2) {  
  needs &= ~KERNEL_INITRD;  
  free(newLine->elements[1].item);  
                 if (new->multiboot && !template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("module");  
                     newLine->type = LT_MBMODULE;  
                 }  
                 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_MBMODULE &&  
                        tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {  
  needs &= ~KERNEL_INITRD;  
                 if (!new->multiboot && template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("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;  
3728    
3729   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3730      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3731      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3732        config->cfi->mbInitRdIsModule) {
3733        /* make sure we don't insert the module initrd
3734         * before the module kernel... if we don't do it here,
3735         * it will be inserted following the template.
3736         */
3737        if (!needs & NEED_KERNEL) {
3738     char *initrdVal;
3739    
3740     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3741     newLine = addLine(new, config->cfi, LT_MBMODULE,
3742      config->secondaryIndent,
3743      initrdVal);
3744     free(initrdVal);
3745     needs &= ~NEED_INITRD;
3746        }
3747     } else if (needs & NEED_INITRD) {
3748        char *initrdVal;
3749        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3750        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3751        free(initrdVal);
3752        needs &= ~NEED_INITRD;
3753   }   }
3754    
3755   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3756   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3757   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3758     char *nkt = malloc(strlen(newKernelTitle)+3);
3759     strcpy(nkt, "'");
3760     strcat(nkt, newKernelTitle);
3761     strcat(nkt, "'");
3762     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3763     free(nkt);
3764     needs &= ~NEED_TITLE;
3765      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3766                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3767                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3768                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3769                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3770                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3771                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3772                                             newLine->numElements);     config->cfi->titleBracketed) {
3773        /* addLineTmpl doesn't handle titleBracketed */
3774                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3775                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3776                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3777                  newLine->numElements = 1;   }
3778              }      } else if (tmplLine->type == LT_ECHO) {
3779        requote(tmplLine, config->cfi);
3780        static const char *prefix = "'Loading ";
3781        if (tmplLine->numElements > 1 &&
3782        strstr(tmplLine->elements[1].item, prefix) &&
3783        masterLine->next &&
3784        iskernel(masterLine->next->type)) {
3785     char *newTitle = malloc(strlen(prefix) +
3786     strlen(newKernelTitle) + 2);
3787    
3788     strcpy(newTitle, prefix);
3789     strcat(newTitle, newKernelTitle);
3790     strcat(newTitle, "'");
3791     newLine = addLine(new, config->cfi, LT_ECHO,
3792     tmplLine->indent, newTitle);
3793     free(newTitle);
3794        } else {
3795     /* pass through other lines from the template */
3796     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3797     config->cfi);
3798        }
3799        } else {
3800     /* pass through other lines from the template */
3801     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3802        }
3803   }   }
3804    
3805      } else {      } else {
3806   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3807      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3808     */
3809     switch (config->cfi->entryStart) {
3810        case LT_KERNEL:
3811        case LT_KERNEL_EFI:
3812     if (new->multiboot && config->cfi->mbHyperFirst) {
3813        /* fall through to LT_HYPER */
3814     } else {
3815        newLine = addLine(new, config->cfi,
3816              preferredLineType(LT_KERNEL, config->cfi),
3817          config->primaryIndent,
3818          newKernelPath + strlen(prefix));
3819        needs &= ~NEED_KERNEL;
3820        break;
3821     }
3822    
3823        case LT_HYPER:
3824     newLine = addLine(new, config->cfi, LT_HYPER,
3825      config->primaryIndent,
3826      newMBKernel + strlen(prefix));
3827     needs &= ~NEED_MB;
3828   break;   break;
         }  
3829    
3830   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3831      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3832       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3833       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3834      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3835       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3836      default:        config->primaryIndent, nkt);
3837                  /* zipl strikes again */   free(nkt);
3838                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3839                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3840                      chptr = newKernelTitle;   break;
3841                      type = LT_TITLE;      }
3842                      break;      case LT_TITLE:
3843                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3844                      abort();   char * templabel;
3845                  }   int x = 0, y = 0;
3846   }  
3847     templabel = strdup(newKernelTitle);
3848     while( templabel[x]){
3849     if( templabel[x] == ' ' ){
3850     y = x;
3851     while( templabel[y] ){
3852     templabel[y] = templabel[y+1];
3853     y++;
3854     }
3855     }
3856     x++;
3857     }
3858     newLine = addLine(new, config->cfi, LT_TITLE,
3859      config->primaryIndent, templabel);
3860     free(templabel);
3861     }else{
3862     newLine = addLine(new, config->cfi, LT_TITLE,
3863      config->primaryIndent, newKernelTitle);
3864     }
3865     needs &= ~NEED_TITLE;
3866     break;
3867    
3868   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3869   new->lines = newLine;   abort();
3870     }
3871      }      }
3872    
3873      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3874          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3875              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3876                                config->secondaryIndent,       */
3877                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3878          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3879              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3880                                config->secondaryIndent,    newKernelTitle);
3881                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3882          /* don't need to check for title as it's guaranteed to have been      }
3883           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3884           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3885          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3886              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3887                                config->secondaryIndent,   needs &= ~NEED_MB;
3888                                newKernelInitrd + strlen(prefix));      }
3889      } else {      if (needs & NEED_KERNEL) {
3890          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3891              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3892                                config->secondaryIndent,        config->cfi))
3893                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3894          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3895              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3896                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3897                                newKernelTitle);   needs &= ~NEED_KERNEL;
3898          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3899              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3900                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3901                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3902      newMBKernel + strlen(prefix));
3903     needs &= ~NEED_MB;
3904        }
3905        if (needs & NEED_INITRD) {
3906     char *initrdVal;
3907     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3908     newLine = addLine(new, config->cfi,
3909      (new->multiboot && getKeywordByType(LT_MBMODULE,
3910          config->cfi))
3911       ? LT_MBMODULE
3912       : preferredLineType(LT_INITRD, config->cfi),
3913      config->secondaryIndent,
3914      initrdVal);
3915     free(initrdVal);
3916     needs &= ~NEED_INITRD;
3917        }
3918        if (needs & NEED_END) {
3919     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3920     config->secondaryIndent, NULL);
3921     needs &= ~NEED_END;
3922        }
3923    
3924        if (needs) {
3925     printf(_("grubby: needs=%d, aborting\n"), needs);
3926     abort();
3927      }      }
3928    
3929      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3932  int addNewKernel(struct grubConfig * con
3932      return 0;      return 0;
3933  }  }
3934    
3935    static void traceback(int signum)
3936    {
3937        void *array[40];
3938        size_t size;
3939    
3940        signal(SIGSEGV, SIG_DFL);
3941        memset(array, '\0', sizeof (array));
3942        size = backtrace(array, 40);
3943    
3944        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
3945                (unsigned long)size);
3946        backtrace_symbols_fd(array, size, STDERR_FILENO);
3947        exit(1);
3948    }
3949    
3950  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3951      poptContext optCon;      poptContext optCon;
3952      char * grubConfig = NULL;      const char * grubConfig = NULL;
3953      char * outputFile = NULL;      char * outputFile = NULL;
3954      int arg = 0;      int arg = 0;
3955      int flags = 0;      int flags = 0;
3956      int badImageOkay = 0;      int badImageOkay = 0;
3957        int configureGrub2 = 0;
3958      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3959      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3960        int configureExtLinux = 0;
3961      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3962        int extraInitrdCount = 0;
3963      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3964      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3965      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3975  int main(int argc, const char ** argv) {
3975      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3976      char * removeArgs = NULL;      char * removeArgs = NULL;
3977      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3978        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3979        char * envPath = NULL;
3980      const char * chptr = NULL;      const char * chptr = NULL;
3981      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3982      struct grubConfig * config;      struct grubConfig * config;
3983      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3984      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3985      int displayDefault = 0;      int displayDefault = 0;
3986        int displayDefaultIndex = 0;
3987        int displayDefaultTitle = 0;
3988        int defaultIndex = -1;
3989      struct poptOption options[] = {      struct poptOption options[] = {
3990   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3991      _("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 4003  int main(int argc, const char ** argv) {
4003   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4004      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4005      _("bootfs") },      _("bootfs") },
4006  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4007   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4008      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4009  #endif  #endif
4010   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4011      _("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 4016  int main(int argc, const char ** argv) {
4016        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4017        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4018        "template"), NULL },        "template"), NULL },
4019     { "debug", 0, 0, &debug, 0,
4020        _("print debugging information for failures") },
4021   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4022      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4023     { "default-index", 0, 0, &displayDefaultIndex, 0,
4024        _("display the index of the default kernel") },
4025     { "default-title", 0, 0, &displayDefaultTitle, 0,
4026        _("display the title of the default kernel") },
4027   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4028      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4029     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4030        _("force grub2 stanzas to use efi") },
4031     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4032        _("path for environment data"),
4033        _("path") },
4034     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4035        _("configure extlinux bootloader (from syslinux)") },
4036   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4037      _("configure grub bootloader") },      _("configure grub bootloader") },
4038     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4039        _("configure grub2 bootloader") },
4040   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4041      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4042      _("kernel-path") },      _("kernel-path") },
4043   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4044      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4045     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4046        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4047   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4048      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4049   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4063  int main(int argc, const char ** argv) {
4063   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4064      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4065        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4066     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4067        _("make the given entry index the default entry"),
4068        _("entry-index") },
4069   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4070      _("configure silo bootloader") },      _("configure silo bootloader") },
4071   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4083  int main(int argc, const char ** argv) {
4083   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4084      };      };
4085    
4086        useextlinuxmenu=0;
4087    
4088        signal(SIGSEGV, traceback);
4089    
4090        int i = 0;
4091        for (int j = 1; j < argc; j++)
4092     i += strlen(argv[j]) + 1;
4093        saved_command_line = malloc(i);
4094        if (!saved_command_line) {
4095     fprintf(stderr, "grubby: %m\n");
4096     exit(1);
4097        }
4098        saved_command_line[0] = '\0';
4099        for (int j = 1; j < argc; j++) {
4100     strcat(saved_command_line, argv[j]);
4101     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4102        }
4103    
4104      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4105      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4106    
# Line 2391  int main(int argc, const char ** argv) { Line 4110  int main(int argc, const char ** argv) {
4110      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4111      exit(0);      exit(0);
4112      break;      break;
4113      case 'i':
4114        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4115         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4116        } else {
4117     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4118     return 1;
4119        }
4120        break;
4121   }   }
4122      }      }
4123    
# Line 2406  int main(int argc, const char ** argv) { Line 4133  int main(int argc, const char ** argv) {
4133   return 1;   return 1;
4134      }      }
4135    
4136      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4137   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4138     configureExtLinux ) > 1) {
4139   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4140   return 1;   return 1;
4141      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4142   fprintf(stderr,   fprintf(stderr,
4143      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4144   return 1;   return 1;
4145        } else if (configureGrub2) {
4146     cfi = &grub2ConfigType;
4147     if (envPath)
4148        cfi->envFile = envPath;
4149      } else if (configureLilo) {      } else if (configureLilo) {
4150   cfi = &liloConfigType;   cfi = &liloConfigType;
4151      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4158  int main(int argc, const char ** argv) {
4158          cfi = &siloConfigType;          cfi = &siloConfigType;
4159      } else if (configureZipl) {      } else if (configureZipl) {
4160          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4161        } else if (configureExtLinux) {
4162     cfi = &extlinuxConfigType;
4163     useextlinuxmenu=1;
4164      }      }
4165    
4166      if (!cfi) {      if (!cfi) {
4167            if (grub2FindConfig(&grub2ConfigType))
4168        cfi = &grub2ConfigType;
4169     else
4170        #ifdef __ia64__        #ifdef __ia64__
4171   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4172        #elif __powerpc__        #elif __powerpc__
4173   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4174        #elif __sparc__        #elif __sparc__
4175          cfi = &siloConfigType;              cfi = &siloConfigType;
4176        #elif __s390__        #elif __s390__
4177          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4178        #elif __s390x__        #elif __s390x__
4179          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4180        #else        #else
4181   cfi = &grubConfigType;      cfi = &grubConfigType;
4182        #endif        #endif
4183      }      }
4184    
4185      if (!grubConfig)      if (!grubConfig) {
4186   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4187        grubConfig = cfi->findConfig(cfi);
4188     if (!grubConfig)
4189        grubConfig = cfi->defaultConfig;
4190        }
4191    
4192      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4193    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4194    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4195        (defaultIndex >= 0))) {
4196   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4197    "specified option"));    "specified option"));
4198   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4208  int main(int argc, const char ** argv) {
4208      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4209   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4210   return 1;   return 1;
4211      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4212    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4213    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4214   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4215   return 1;   return 1;
4216      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4234  int main(int argc, const char ** argv) {
4234   makeDefault = 1;   makeDefault = 1;
4235   defaultKernel = NULL;   defaultKernel = NULL;
4236      }      }
4237        else if (defaultKernel && (defaultIndex >= 0)) {
4238     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4239      "may not be used together\n"));
4240     return 1;
4241        }
4242    
4243      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4244   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4245   "is used\n"));   "is used\n"));
4246   return 1;   return 1;
4247      }      }
4248    
4249      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4250   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4251          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4252     && (defaultIndex == -1)) {
4253   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4254   return 1;   return 1;
4255      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4269  int main(int argc, const char ** argv) {
4269   bootPrefix = "";   bootPrefix = "";
4270      }      }
4271    
4272        if (!cfi->mbAllowExtraInitRds &&
4273     extraInitrdCount > 0) {
4274     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4275     return 1;
4276        }
4277    
4278      if (bootloaderProbe) {      if (bootloaderProbe) {
4279   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4280   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4281    
4282     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4283     if (grub2config) {
4284        gconfig = readConfig(grub2config, &grub2ConfigType);
4285        if (!gconfig)
4286     gr2c = 1;
4287        else
4288     gr2c = checkForGrub2(gconfig);
4289     }
4290    
4291   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4292      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4293        gconfig = readConfig(grubconfig, &grubConfigType);
4294      if (!gconfig)      if (!gconfig)
4295   grc = 1;   grc = 1;
4296      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4305  int main(int argc, const char ** argv) {
4305   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4306   }   }
4307    
4308   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4309        econfig = readConfig(eliloConfigType.defaultConfig,
4310     &eliloConfigType);
4311        if (!econfig)
4312     erc = 1;
4313        else
4314     erc = checkForElilo(econfig);
4315     }
4316    
4317     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4318        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4319        if (!lconfig)
4320     extrc = 1;
4321        else
4322     extrc = checkForExtLinux(lconfig);
4323     }
4324    
4325    
4326     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4327        yconfig = readConfig(yabootConfigType.defaultConfig,
4328     &yabootConfigType);
4329        if (!yconfig)
4330     yrc = 1;
4331        else
4332     yrc = checkForYaboot(yconfig);
4333     }
4334    
4335     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4336     erc == 1)
4337        return 1;
4338    
4339   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4340     if (gr2c == 2) printf("grub2\n");
4341   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4342     if (extrc == 2) printf("extlinux\n");
4343     if (yrc == 2) printf("yaboot\n");
4344     if (erc == 2) printf("elilo\n");
4345    
4346   return 0;   return 0;
4347      }      }
4348    
4349        if (grubConfig == NULL) {
4350     printf("Could not find bootloader configuration file.\n");
4351     exit(1);
4352        }
4353    
4354      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4355      if (!config) return 1;      if (!config) return 1;
4356    
# Line 2557  int main(int argc, const char ** argv) { Line 4360  int main(int argc, const char ** argv) {
4360          char * rootspec;          char * rootspec;
4361    
4362   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4363     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4364     cfi->defaultIsSaved)
4365        config->defaultImage = 0;
4366   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4367   if (!entry) return 0;   if (!entry) return 0;
4368   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4369    
4370   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4371   if (!line) return 0;   if (!line) return 0;
4372    
4373          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4375  int main(int argc, const char ** argv) {
4375                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4376    
4377   return 0;   return 0;
4378    
4379        } else if (displayDefaultTitle) {
4380     struct singleLine * line;
4381     struct singleEntry * entry;
4382    
4383     if (config->defaultImage == -1) return 0;
4384     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4385     cfi->defaultIsSaved)
4386        config->defaultImage = 0;
4387     entry = findEntryByIndex(config, config->defaultImage);
4388     if (!entry) return 0;
4389    
4390     if (!configureGrub2) {
4391      line = getLineByType(LT_TITLE, entry->lines);
4392      if (!line) return 0;
4393      printf("%s\n", line->elements[1].item);
4394    
4395     } else {
4396      char * title;
4397    
4398      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4399      line = getLineByType(LT_MENUENTRY, entry->lines);
4400      if (!line) return 0;
4401      title = grub2ExtractTitle(line);
4402      if (title)
4403        printf("%s\n", title);
4404     }
4405     return 0;
4406    
4407        } else if (displayDefaultIndex) {
4408            if (config->defaultImage == -1) return 0;
4409     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4410     cfi->defaultIsSaved)
4411        config->defaultImage = 0;
4412            printf("%i\n", config->defaultImage);
4413            return 0;
4414    
4415      } else if (kernelInfo)      } else if (kernelInfo)
4416   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4417    
# Line 2581  int main(int argc, const char ** argv) { Line 4423  int main(int argc, const char ** argv) {
4423      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4424      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4425      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4426      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4427      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4428      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4429                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4430        if (updateKernelPath && newKernelInitrd) {
4431                if (updateInitrd(config, updateKernelPath, bootPrefix,
4432                                 newKernelInitrd)) return 1;
4433        }
4434      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4435                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4436                         (const char **)extraInitrds, extraInitrdCount,
4437                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4438            
4439    
# Line 2597  int main(int argc, const char ** argv) { Line 4444  int main(int argc, const char ** argv) {
4444      }      }
4445    
4446      if (!outputFile)      if (!outputFile)
4447   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4448    
4449      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4450  }  }

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