Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 2258 by niro, Mon Oct 21 14:02:25 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 sPopCount(const char *s, const char *c)
301    {
302        int ret = 0;
303        if (!s)
304     return -1;
305        for (int i = 0; s[i] != '\0'; i++)
306     for (int j = 0; c[j] != '\0'; j++)
307        if (s[i] == c[j])
308     ret++;
309        return ret;
310    }
311    
312    static char *shellEscape(const char *s)
313    {
314        int l = strlen(s) + sPopCount(s, "'") * 2;
315    
316        char *ret = calloc(l+1, sizeof (*ret));
317        if (!ret)
318     return NULL;
319        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
320     if (s[i] == '\'')
321        ret[j++] = '\\';
322     ret[j] = s[i];
323        }
324        return ret;
325    }
326    
327    static void unquote(char *s)
328    {
329        int l = strlen(s);
330    
331        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
332     memmove(s, s+1, l-2);
333     s[l-2] = '\0';
334        }
335    }
336    
337    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
338    {
339        char *s = NULL;
340        int rc = 0;
341        char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
342    
343        unquote(value);
344        value = shellEscape(value);
345        if (!value)
346        return -1;
347    
348        rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value);
349        free(value);
350        if (rc <0)
351     return -1;
352    
353        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
354        rc = system(s);
355        free(s);
356        return rc;
357    }
358    
359    /* this is a gigantic hack to avoid clobbering grub2 variables... */
360    static int is_special_grub2_variable(const char *name)
361    {
362        if (!strcmp(name,"\"${next_entry}\""))
363     return 1;
364        if (!strcmp(name,"\"${prev_saved_entry}\""))
365     return 1;
366        return 0;
367    }
368    
369    int sizeOfSingleLine(struct singleLine * line) {
370      int count = 0;
371    
372      for (int i = 0; i < line->numElements; i++) {
373        int indentSize = 0;
374    
375        count = count + strlen(line->elements[i].item);
376    
377        indentSize = strlen(line->elements[i].indent);
378        if (indentSize > 0)
379          count = count + indentSize;
380        else
381          /* be extra safe and add room for whitespaces */
382          count = count + 1;
383      }
384    
385      /* room for trailing terminator */
386      count = count + 1;
387    
388      return count;
389    }
390    
391    static int isquote(char q)
392    {
393        if (q == '\'' || q == '\"')
394     return 1;
395        return 0;
396    }
397    
398    static int iskernel(enum lineType_e type) {
399        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
400    }
401    
402    static int isinitrd(enum lineType_e type) {
403        return (type == LT_INITRD || type == LT_INITRD_EFI);
404    }
405    
406    char *grub2ExtractTitle(struct singleLine * line) {
407        char * current;
408        char * current_indent;
409        int current_len;
410        int current_indent_len;
411        int i;
412    
413        /* bail out if line does not start with menuentry */
414        if (strcmp(line->elements[0].item, "menuentry"))
415          return NULL;
416    
417        i = 1;
418        current = line->elements[i].item;
419        current_len = strlen(current);
420    
421        /* if second word is quoted, strip the quotes and return single word */
422        if (isquote(*current) && isquote(current[current_len - 1])) {
423     char *tmp;
424    
425     tmp = strdup(current);
426     *(tmp + current_len - 1) = '\0';
427     return ++tmp;
428        }
429    
430        /* if no quotes, return second word verbatim */
431        if (!isquote(*current))
432     return current;
433    
434        /* second element start with a quote, so we have to find the element
435         * whose last character is also quote (assuming it's the closing one) */
436        int resultMaxSize;
437        char * result;
438        
439        resultMaxSize = sizeOfSingleLine(line);
440        result = malloc(resultMaxSize);
441        snprintf(result, resultMaxSize, "%s", ++current);
442        
443        i++;
444        for (; i < line->numElements; ++i) {
445     current = line->elements[i].item;
446     current_len = strlen(current);
447     current_indent = line->elements[i].indent;
448     current_indent_len = strlen(current_indent);
449    
450     strncat(result, current_indent, current_indent_len);
451     if (!isquote(current[current_len-1])) {
452        strncat(result, current, current_len);
453     } else {
454        strncat(result, current, current_len - 1);
455        break;
456     }
457        }
458        return result;
459    }
460    
461    struct configFileInfo grub2ConfigType = {
462        .findConfig = grub2FindConfig,
463        .getEnv = grub2GetEnv,
464        .setEnv = grub2SetEnv,
465        .keywords = grub2Keywords,
466        .defaultIsIndex = 1,
467        .defaultSupportSaved = 1,
468        .defaultIsVariable = 1,
469        .entryStart = LT_MENUENTRY,
470        .entryEnd = LT_ENTRY_END,
471        .titlePosition = 1,
472        .needsBootPrefix = 1,
473        .mbHyperFirst = 1,
474        .mbInitRdIsModule = 1,
475        .mbAllowExtraInitRds = 1,
476  };  };
477    
478  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 506  struct keywordTypes yabootKeywords[] = {
506      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
507      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
508      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
509      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
510      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
511      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
512      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 526  struct keywordTypes liloKeywords[] = {
526      { NULL,    0, 0 },      { NULL,    0, 0 },
527  };  };
528    
529    struct keywordTypes eliloKeywords[] = {
530        { "label",    LT_TITLE,    '=' },
531        { "root",    LT_ROOT,    '=' },
532        { "default",    LT_DEFAULT,    '=' },
533        { "image",    LT_KERNEL,    '=' },
534        { "initrd",    LT_INITRD,    '=' },
535        { "append",    LT_KERNELARGS,  '=' },
536        { "vmm",    LT_HYPER,       '=' },
537        { NULL,    0, 0 },
538    };
539    
540  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
541      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
542      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 558  struct keywordTypes ziplKeywords[] = {
558      { NULL,         0, 0 },      { NULL,         0, 0 },
559  };  };
560    
561    struct keywordTypes extlinuxKeywords[] = {
562        { "label",    LT_TITLE,    ' ' },
563        { "root",    LT_ROOT,    ' ' },
564        { "default",    LT_DEFAULT,    ' ' },
565        { "kernel",    LT_KERNEL,    ' ' },
566        { "initrd",    LT_INITRD,      ' ', ',' },
567        { "append",    LT_KERNELARGS,  ' ' },
568        { "prompt",     LT_UNKNOWN,     ' ' },
569        { NULL,    0, 0 },
570    };
571    int useextlinuxmenu;
572  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
573      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
574      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
575      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
576      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
577      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
578      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
579  };  };
580    
581  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
582      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
583      liloKeywords,    /* keywords */      .keywords = liloKeywords,
584      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
585      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
586      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
587  };  };
588    
589  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
590      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
591      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
592      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
593      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
594      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
595      1,    /* needsBootPrefix */      .maxTitleLength = 15,
596      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
597  };  };
598    
599  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
600      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
601      siloKeywords,    /* keywords */      .keywords = siloKeywords,
602      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
603      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
604      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
605      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
606  };  };
607    
608  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
609      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
610      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
611      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
612      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
613      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
614      0,    /* needsBootPrefix */  };
615      1,    /* argsInQuotes */  
616      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
617      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
618        .keywords = extlinuxKeywords,
619        .caseInsensitive = 1,
620        .entryStart = LT_TITLE,
621        .needsBootPrefix = 1,
622        .maxTitleLength = 255,
623        .mbAllowExtraInitRds = 1,
624  };  };
625    
626  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 635  struct grubConfig {
635      struct configFileInfo * cfi;      struct configFileInfo * cfi;
636  };  };
637    
638    blkid_cache blkid;
639    
640  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
641  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
642       const char * path, const char * prefix,       const char * path, const char * prefix,
643       int * index);       int * index);
644  static char * strndup(char * from, int len);  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
645          int * index);
646  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
647  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
648    struct singleLine * lineDup(struct singleLine * line);
649  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
650  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
651       struct configFileInfo * cfi);       struct configFileInfo * cfi);
652  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
653         struct configFileInfo * cfi);         struct configFileInfo * cfi);
654  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
655    static void requote(struct singleLine *line, struct configFileInfo * cfi);
656  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
657      char * to;    const char * item, int insertHere,
658      struct configFileInfo * cfi);
659      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
660      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
661      to[len] = '\0';        struct configFileInfo * cfi);
662    static enum lineType_e getTypeByKeyword(char * keyword,
663      return to;   struct configFileInfo * cfi);
664  }  static struct singleLine * getLineByType(enum lineType_e type,
665     struct singleLine * line);
666    static int checkForExtLinux(struct grubConfig * config);
667    struct singleLine * addLineTmpl(struct singleEntry * entry,
668                                    struct singleLine * tmplLine,
669                                    struct singleLine * prevLine,
670                                    const char * val,
671     struct configFileInfo * cfi);
672    struct singleLine *  addLine(struct singleEntry * entry,
673                                 struct configFileInfo * cfi,
674                                 enum lineType_e type, char * defaultIndent,
675                                 const char * val);
676    
677  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
678  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 707  static char * sdupprintf(const char *for
707      return buf;      return buf;
708  }  }
709    
710    static enum lineType_e preferredLineType(enum lineType_e type,
711     struct configFileInfo *cfi) {
712        if (isEfi && cfi == &grub2ConfigType) {
713     switch (type) {
714     case LT_KERNEL:
715        return LT_KERNEL_EFI;
716     case LT_INITRD:
717        return LT_INITRD_EFI;
718     default:
719        return type;
720     }
721        }
722        return type;
723    }
724    
725    static struct keywordTypes * getKeywordByType(enum lineType_e type,
726          struct configFileInfo * cfi) {
727        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
728     if (kw->type == type)
729        return kw;
730        }
731        return NULL;
732    }
733    
734    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
735        struct keywordTypes *kt = getKeywordByType(type, cfi);
736        if (kt)
737     return kt->key;
738        return "unknown";
739    }
740    
741    static char * getpathbyspec(char *device) {
742        if (!blkid)
743            blkid_get_cache(&blkid, NULL);
744    
745        return blkid_get_devname(blkid, device, NULL);
746    }
747    
748    static char * getuuidbydev(char *device) {
749        if (!blkid)
750     blkid_get_cache(&blkid, NULL);
751    
752        return blkid_get_tag_value(blkid, "UUID", device);
753    }
754    
755    static enum lineType_e getTypeByKeyword(char * keyword,
756     struct configFileInfo * cfi) {
757        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
758     if (cfi->caseInsensitive) {
759        if (!strcasecmp(keyword, kw->key))
760                    return kw->type;
761     } else {
762        if (!strcmp(keyword, kw->key))
763            return kw->type;
764     }
765        }
766        return LT_UNKNOWN;
767    }
768    
769    static struct singleLine * getLineByType(enum lineType_e type,
770     struct singleLine * line) {
771        dbgPrintf("getLineByType(%d): ", type);
772        for (; line; line = line->next) {
773     dbgPrintf("%d:%s ", line->type,
774      line->numElements ? line->elements[0].item : "(empty)");
775     if (line->type & type) break;
776        }
777        dbgPrintf(line ? "\n" : " (failed)\n");
778        return line;
779    }
780    
781  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
782      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
783          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
784          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
785              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 791  static int isBracketedTitle(struct singl
791      return 0;      return 0;
792  }  }
793    
794  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
795                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
796      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
797   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;  
798  }  }
799    
800  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
801  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
802      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
803      char * title;      char * title = NULL;
804      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
805      title++;   title = strdup(line->elements[0].item);
806      *(title + strlen(title) - 1) = '\0';   title++;
807     *(title + strlen(title) - 1) = '\0';
808        } else if (line->type == LT_MENUENTRY)
809     title = strdup(line->elements[1].item);
810        else
811     return NULL;
812      return title;      return title;
813  }  }
814    
# Line 389  static void lineInit(struct singleLine * Line 850  static void lineInit(struct singleLine *
850      line->next = NULL;      line->next = NULL;
851  }  }
852    
853  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
854      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
855    
856        newLine->indent = strdup(line->indent);
857        newLine->next = NULL;
858        newLine->type = line->type;
859        newLine->numElements = line->numElements;
860        newLine->elements = malloc(sizeof(*newLine->elements) *
861           newLine->numElements);
862    
863        for (int i = 0; i < newLine->numElements; i++) {
864     newLine->elements[i].indent = strdup(line->elements[i].indent);
865     newLine->elements[i].item = strdup(line->elements[i].item);
866        }
867    
868        return newLine;
869    }
870    
871    static void lineFree(struct singleLine * line) {
872      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
873    
874      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
875   free(line->elements[i].item);   free(line->elements[i].item);
876   free(line->elements[i].indent);   free(line->elements[i].indent);
877      }      }
# Line 405  static void lineFree(struct singleLine * Line 882  static void lineFree(struct singleLine *
882    
883  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
884       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
885      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
886    
887      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
888     /* Need to handle this, because we strip the quotes from
889     * menuentry when read it. */
890     if (line->type == LT_MENUENTRY && i == 1) {
891        if(!isquote(*line->elements[i].item))
892     fprintf(out, "\'%s\'", line->elements[i].item);
893        else
894     fprintf(out, "%s", line->elements[i].item);
895        fprintf(out, "%s", line->elements[i].indent);
896    
897        continue;
898     }
899    
900   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
901      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
902    
903   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
904   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
905        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
906      }      }
907    
908      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 921  static int getNextLine(char ** bufPtr, s
921      char * chptr;      char * chptr;
922      int elementsAlloced = 0;      int elementsAlloced = 0;
923      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
924      int first = 1;      int first = 1;
     int i;  
925    
926      lineFree(line);      lineFree(line);
927    
# Line 489  static int getNextLine(char ** bufPtr, s Line 975  static int getNextLine(char ** bufPtr, s
975      if (!line->numElements)      if (!line->numElements)
976   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
977      else {      else {
978   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
979      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;  
               
980              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
981               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
982              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 990  static int getNextLine(char ** bufPtr, s
990      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
991   char * fullLine;   char * fullLine;
992   int len;   int len;
  int i;  
993    
994   len = strlen(line->indent);   len = strlen(line->indent);
995   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
996      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
997     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
998    
# Line 522  static int getNextLine(char ** bufPtr, s Line 1001  static int getNextLine(char ** bufPtr, s
1001   free(line->indent);   free(line->indent);
1002   line->indent = fullLine;   line->indent = fullLine;
1003    
1004   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1005      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1006      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1007      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 1011  static int getNextLine(char ** bufPtr, s
1011   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
1012   line->numElements = 0;   line->numElements = 0;
1013      }      }
1014     } else {
1015     struct keywordTypes *kw;
1016    
1017     kw = getKeywordByType(line->type, cfi);
1018    
1019     /* space isn't the only separator, we need to split
1020     * elements up more
1021     */
1022     if (!isspace(kw->separatorChar)) {
1023        char indent[2] = "";
1024        indent[0] = kw->separatorChar;
1025        for (int i = 1; i < line->numElements; i++) {
1026     char *p;
1027     int numNewElements;
1028    
1029     numNewElements = 0;
1030     p = line->elements[i].item;
1031     while (*p != '\0') {
1032     if (*p == kw->separatorChar)
1033     numNewElements++;
1034     p++;
1035     }
1036     if (line->numElements + numNewElements >= elementsAlloced) {
1037     elementsAlloced += numNewElements + 5;
1038     line->elements = realloc(line->elements,
1039        sizeof(*line->elements) * elementsAlloced);
1040     }
1041    
1042     for (int j = line->numElements; j > i; j--) {
1043     line->elements[j + numNewElements] = line->elements[j];
1044     }
1045     line->numElements += numNewElements;
1046    
1047     p = line->elements[i].item;
1048     while (*p != '\0') {
1049    
1050     while (*p != kw->separatorChar && *p != '\0') p++;
1051     if (*p == '\0') {
1052     break;
1053     }
1054    
1055     line->elements[i + 1].indent = line->elements[i].indent;
1056     line->elements[i].indent = strdup(indent);
1057     *p++ = '\0';
1058     i++;
1059     line->elements[i].item = strdup(p);
1060     }
1061        }
1062     }
1063   }   }
1064      }      }
1065    
1066      return 0;      return 0;
1067  }  }
1068    
1069    static int isnumber(const char *s)
1070    {
1071        int i;
1072        for (i = 0; s[i] != '\0'; i++)
1073     if (s[i] < '0' || s[i] > '9')
1074        return 0;
1075        return i;
1076    }
1077    
1078  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1079        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1080      int in;      int in;
# Line 549  static struct grubConfig * readConfig(co Line 1086  static struct grubConfig * readConfig(co
1086      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1087      char * end;      char * end;
1088      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1089      int i, len;      int len;
1090      char * buf;      char * buf;
1091    
1092      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1093            printf("Could not find bootloader configuration\n");
1094            exit(1);
1095        } else if (!strcmp(inName, "-")) {
1096   in = 0;   in = 0;
1097      } else {      } else {
1098   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1135  static struct grubConfig * readConfig(co
1135      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1136   }   }
1137    
1138   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1139      sawEntry = 1;      sawEntry = 1;
1140      if (!entry) {      if (!entry) {
1141   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1151  static struct grubConfig * readConfig(co
1151      entry->next = NULL;      entry->next = NULL;
1152   }   }
1153    
1154   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1155        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1156        dbgPrintf("%s", line->indent);
1157        for (int i = 0; i < line->numElements; i++)
1158     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1159        dbgPrintf("\n");
1160        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1161        if (kwType && line->numElements == 3 &&
1162        !strcmp(line->elements[1].item, kwType->key) &&
1163        !is_special_grub2_variable(line->elements[2].item)) {
1164     dbgPrintf("Line sets default config\n");
1165     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1166     defaultLine = line;
1167        }
1168     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1169      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1170      defaultLine = line;      defaultLine = line;
1171    
1172            } else if (iskernel(line->type)) {
1173        /* if by some freak chance this is multiboot and the "module"
1174         * lines came earlier in the template, make sure to use LT_HYPER
1175         * instead of LT_KERNEL now
1176         */
1177        if (entry->multiboot)
1178     line->type = LT_HYPER;
1179    
1180          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1181        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1182         * instead, now that we know this is a multiboot entry.
1183         * This only applies to grub, but that's the only place we
1184         * should find LT_MBMODULE lines anyway.
1185         */
1186        for (struct singleLine *l = entry->lines; l; l = l->next) {
1187     if (l->type == LT_HYPER)
1188        break;
1189     else if (iskernel(l->type)) {
1190        l->type = LT_HYPER;
1191        break;
1192     }
1193        }
1194              entry->multiboot = 1;              entry->multiboot = 1;
1195    
1196     } else if (line->type == LT_HYPER) {
1197        entry->multiboot = 1;
1198    
1199   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1200      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1201      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1202    
1203   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1204      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1205      len = 0;      len = 0;
1206      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1207   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1208   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1209      }      }
1210      buf = malloc(len + 1);      buf = malloc(len + 1);
1211      *buf = '\0';      *buf = '\0';
1212    
1213      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1214   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1215   free(line->elements[i].item);   free(line->elements[i].item);
1216    
# Line 643  static struct grubConfig * readConfig(co Line 1224  static struct grubConfig * readConfig(co
1224      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1225      line->elements[1].item = buf;      line->elements[1].item = buf;
1226      line->numElements = 2;      line->numElements = 2;
1227     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1228        /* let --remove-kernel="TITLE=what" work */
1229        len = 0;
1230        char *extras;
1231        char *title;
1232    
1233        for (int i = 1; i < line->numElements; i++) {
1234     len += strlen(line->elements[i].item);
1235     len += strlen(line->elements[i].indent);
1236        }
1237        buf = malloc(len + 1);
1238        *buf = '\0';
1239    
1240        /* allocate mem for extra flags. */
1241        extras = malloc(len + 1);
1242        *extras = '\0';
1243    
1244        /* get title. */
1245        for (int i = 0; i < line->numElements; i++) {
1246     if (!strcmp(line->elements[i].item, "menuentry"))
1247        continue;
1248     if (isquote(*line->elements[i].item))
1249        title = line->elements[i].item + 1;
1250     else
1251        title = line->elements[i].item;
1252    
1253     len = strlen(title);
1254            if (isquote(title[len-1])) {
1255        strncat(buf, title,len-1);
1256        break;
1257     } else {
1258        strcat(buf, title);
1259        strcat(buf, line->elements[i].indent);
1260     }
1261        }
1262    
1263        /* get extras */
1264        int count = 0;
1265        for (int i = 0; i < line->numElements; i++) {
1266     if (count >= 2) {
1267        strcat(extras, line->elements[i].item);
1268        strcat(extras, line->elements[i].indent);
1269     }
1270    
1271     if (!strcmp(line->elements[i].item, "menuentry"))
1272        continue;
1273    
1274     /* count ' or ", there should be two in menuentry line. */
1275     if (isquote(*line->elements[i].item))
1276        count++;
1277    
1278     len = strlen(line->elements[i].item);
1279    
1280     if (isquote(line->elements[i].item[len -1]))
1281        count++;
1282    
1283     /* ok, we get the final ' or ", others are extras. */
1284                }
1285        line->elements[1].indent =
1286     line->elements[line->numElements - 2].indent;
1287        line->elements[1].item = buf;
1288        line->elements[2].indent =
1289     line->elements[line->numElements - 2].indent;
1290        line->elements[2].item = extras;
1291        line->numElements = 3;
1292   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1293      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1294         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 1297  static struct grubConfig * readConfig(co
1297      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1298   int last, len;   int last, len;
1299    
1300   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1301      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1302     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1303    
1304   last = line->numElements - 1;   last = line->numElements - 1;
1305   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1306   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1307      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1308      }      }
   
1309   }   }
1310    
1311   /* 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 1325  static struct grubConfig * readConfig(co
1325   movedLine = 1;   movedLine = 1;
1326   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1327   }   }
1328    
1329   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1330     which was moved, drop it. */     which was moved, drop it. */
1331   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 1341  static struct grubConfig * readConfig(co
1341   entry->lines = line;   entry->lines = line;
1342      else      else
1343   last->next = line;   last->next = line;
1344        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1345    
1346        /* we could have seen this outside of an entry... if so, we
1347         * ignore it like any other line we don't grok */
1348        if (line->type == LT_ENTRY_END && sawEntry)
1349     sawEntry = 0;
1350   } else {   } else {
1351      if (!cfg->theLines)      if (!cfg->theLines)
1352   cfg->theLines = line;   cfg->theLines = line;
1353      else {      else
1354   last->next = line;   last->next = line;
1355      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1356   }   }
1357    
1358   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1360  static struct grubConfig * readConfig(co
1360    
1361      free(incoming);      free(incoming);
1362    
1363        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1364      if (defaultLine) {      if (defaultLine) {
1365   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1366        cfi->defaultSupportSaved &&
1367        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1368     cfg->cfi->defaultIsSaved = 1;
1369     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1370     if (cfg->cfi->getEnv) {
1371        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1372        if (defTitle) {
1373     int index = 0;
1374     if (isnumber(defTitle)) {
1375        index = atoi(defTitle);
1376        entry = findEntryByIndex(cfg, index);
1377     } else {
1378        entry = findEntryByTitle(cfg, defTitle, &index);
1379     }
1380     if (entry)
1381        cfg->defaultImage = index;
1382        }
1383     }
1384     } else if (cfi->defaultIsVariable) {
1385        char *value = defaultLine->elements[2].item;
1386        while (*value && (*value == '"' || *value == '\'' ||
1387        *value == ' ' || *value == '\t'))
1388     value++;
1389        cfg->defaultImage = strtol(value, &end, 10);
1390        while (*end && (*end == '"' || *end == '\'' ||
1391        *end == ' ' || *end == '\t'))
1392     end++;
1393        if (*end) cfg->defaultImage = -1;
1394     } else if (cfi->defaultSupportSaved &&
1395   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1396      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1397   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1398      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1399      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1400   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1401      i = 0;      int i = 0;
1402      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1403   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1404      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1412  static struct grubConfig * readConfig(co
1412                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1413                  }                  }
1414   i++;   i++;
1415     entry = NULL;
1416      }      }
1417    
1418      if (entry) cfg->defaultImage = i;      if (entry){
1419            cfg->defaultImage = i;
1420        }else{
1421            cfg->defaultImage = -1;
1422        }
1423   }   }
1424        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1425     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1426     if (defTitle) {
1427        int index = 0;
1428        if (isnumber(defTitle)) {
1429     index = atoi(defTitle);
1430     entry = findEntryByIndex(cfg, index);
1431        } else {
1432     entry = findEntryByTitle(cfg, defTitle, &index);
1433        }
1434        if (entry)
1435     cfg->defaultImage = index;
1436     }
1437        } else {
1438            cfg->defaultImage = 0;
1439      }      }
1440    
1441      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1451  static void writeDefault(FILE * out, cha
1451    
1452      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1453   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1454      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1455     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1456     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1457        char *title;
1458        entry = findEntryByIndex(cfg, cfg->defaultImage);
1459        line = getLineByType(LT_MENUENTRY, entry->lines);
1460        if (!line)
1461     line = getLineByType(LT_TITLE, entry->lines);
1462        if (line) {
1463     title = extractTitle(line);
1464     if (title)
1465        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1466        }
1467     }
1468        } else if (cfg->defaultImage > -1) {
1469   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1470      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1471      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1472     cfg->defaultImage);
1473        } else {
1474     fprintf(out, "%sdefault%s%d\n", indent, separator,
1475     cfg->defaultImage);
1476        }
1477   } else {   } else {
1478      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1479    
# Line 769  static void writeDefault(FILE * out, cha Line 1490  static void writeDefault(FILE * out, cha
1490    
1491      if (!entry) return;      if (!entry) return;
1492    
1493      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1494    
1495      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1496   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1524  static int writeConfig(struct grubConfig
1524      int rc;      int rc;
1525    
1526      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1527         directory to / */         directory to the dir of the symlink */
1528      rc = chdir("/");      char *dir = strdupa(outName);
1529        rc = chdir(dirname(dir));
1530      do {      do {
1531   buf = alloca(len + 1);   buf = alloca(len + 1);
1532   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1533   if (rc == len) len += 256;   if (rc == len) len += 256;
1534      } while (rc == len);      } while (rc == len);
1535            
# Line 843  static int writeConfig(struct grubConfig Line 1564  static int writeConfig(struct grubConfig
1564      }      }
1565    
1566      line = cfg->theLines;      line = cfg->theLines;
1567        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1568      while (line) {      while (line) {
1569   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1570     line->numElements == 3 &&
1571     !strcmp(line->elements[1].item, defaultKw->key) &&
1572     !is_special_grub2_variable(line->elements[2].item)) {
1573        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1574        needs &= ~MAIN_DEFAULT;
1575     } else if (line->type == LT_DEFAULT) {
1576      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1577      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1578   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1640  static int numEntries(struct grubConfig
1640      return i;      return i;
1641  }  }
1642    
1643  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1644    int skipRemoved, int flags) {  {
1645      struct singleLine * line;      int fd;
1646      char * fullName;      char buf[65536];
1647      int i;      char *devname;
1648      struct stat sb, sb2;      char *chptr;
1649      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1650    
1651      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1652      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1653                        _PATH_MOUNTED, strerror(errno));
1654      if (!line) return 0;          return NULL;
1655      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1656    
1657      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1658        if (rc <= 0) {
1659            fprintf(stderr, "grubby: failed to read %s: %s\n",
1660                    _PATH_MOUNTED, strerror(errno));
1661            close(fd);
1662            return NULL;
1663        }
1664        close(fd);
1665        buf[rc] = '\0';
1666        chptr = buf;
1667    
1668      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;  
1669    
1670      for (i = 2; i < line->numElements; i++)      while (chptr && chptr != buf+rc) {
1671   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          devname = chptr;
1672      if (i < line->numElements) {  
1673   dev = line->elements[i].item + 5;          /*
1674             * The first column of a mtab entry is the device, but if the entry is a
1675             * special device it won't start with /, so move on to the next line.
1676             */
1677            if (*devname != '/') {
1678                chptr = strchr(chptr, '\n');
1679                if (chptr)
1680                    chptr++;
1681                continue;
1682            }
1683    
1684            /* Seek to the next space */
1685            chptr = strchr(chptr, ' ');
1686            if (!chptr) {
1687                fprintf(stderr, "grubby: error parsing %s: %s\n",
1688                        _PATH_MOUNTED, strerror(errno));
1689                return NULL;
1690            }
1691    
1692            /*
1693             * The second column of a mtab entry is the mount point, we are looking
1694             * for '/' obviously.
1695             */
1696            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1697                /* remember the last / entry in mtab */
1698               foundanswer = devname;
1699            }
1700    
1701            /* Next line */
1702            chptr = strchr(chptr, '\n');
1703            if (chptr)
1704                chptr++;
1705        }
1706    
1707        /* Return the last / entry found */
1708        if (foundanswer) {
1709            chptr = strchr(foundanswer, ' ');
1710            *chptr = '\0';
1711            return strdup(foundanswer);
1712        }
1713    
1714        return NULL;
1715    }
1716    
1717    void printEntry(struct singleEntry * entry, FILE *f) {
1718        int i;
1719        struct singleLine * line;
1720    
1721        for (line = entry->lines; line; line = line->next) {
1722     log_message(f, "DBG: %s", line->indent);
1723     for (i = 0; i < line->numElements; i++) {
1724        /* Need to handle this, because we strip the quotes from
1725         * menuentry when read it. */
1726        if (line->type == LT_MENUENTRY && i == 1) {
1727     if(!isquote(*line->elements[i].item))
1728        log_message(f, "\'%s\'", line->elements[i].item);
1729     else
1730        log_message(f, "%s", line->elements[i].item);
1731     log_message(f, "%s", line->elements[i].indent);
1732    
1733     continue;
1734        }
1735        
1736        log_message(f, "%s%s",
1737        line->elements[i].item, line->elements[i].indent);
1738     }
1739     log_message(f, "\n");
1740        }
1741    }
1742    
1743    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1744    {
1745        static int once;
1746        va_list argp, argq;
1747    
1748        va_start(argp, fmt);
1749    
1750        va_copy(argq, argp);
1751        if (!once) {
1752     log_time(NULL);
1753     log_message(NULL, "command line: %s\n", saved_command_line);
1754        }
1755        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1756        log_vmessage(NULL, fmt, argq);
1757    
1758        printEntry(entry, NULL);
1759        va_end(argq);
1760    
1761        if (!debug) {
1762     once = 1;
1763         va_end(argp);
1764     return;
1765        }
1766    
1767        if (okay) {
1768     va_end(argp);
1769     return;
1770        }
1771    
1772        if (!once)
1773     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1774        once = 1;
1775        fprintf(stderr, "DBG: Image entry failed: ");
1776        vfprintf(stderr, fmt, argp);
1777        printEntry(entry, stderr);
1778        va_end(argp);
1779    }
1780    
1781    #define beginswith(s, c) ((s) && (s)[0] == (c))
1782    
1783    static int endswith(const char *s, char c)
1784    {
1785     int slen;
1786    
1787     if (!s || !s[0])
1788     return 0;
1789     slen = strlen(s) - 1;
1790    
1791     return s[slen] == c;
1792    }
1793    
1794    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1795      int skipRemoved, int flags) {
1796        struct singleLine * line;
1797        char * fullName;
1798        int i;
1799        char * dev;
1800        char * rootspec;
1801        char * rootdev;
1802    
1803        if (skipRemoved && entry->skip) {
1804     notSuitablePrintf(entry, 0, "marked to skip\n");
1805     return 0;
1806        }
1807    
1808        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1809        if (!line) {
1810     notSuitablePrintf(entry, 0, "no line found\n");
1811     return 0;
1812        }
1813        if (line->numElements < 2) {
1814     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1815        line->numElements);
1816     return 0;
1817        }
1818    
1819        if (flags & GRUBBY_BADIMAGE_OKAY) {
1820        notSuitablePrintf(entry, 1, "\n");
1821        return 1;
1822        }
1823    
1824        fullName = alloca(strlen(bootPrefix) +
1825          strlen(line->elements[1].item) + 1);
1826        rootspec = getRootSpecifier(line->elements[1].item);
1827        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1828        int hasslash = endswith(bootPrefix, '/') ||
1829         beginswith(line->elements[1].item + rootspec_offset, '/');
1830        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1831                line->elements[1].item + rootspec_offset);
1832        if (access(fullName, R_OK)) {
1833     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1834     return 0;
1835        }
1836        for (i = 2; i < line->numElements; i++)
1837     if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1838        if (i < line->numElements) {
1839     dev = line->elements[i].item + 5;
1840      } else {      } else {
1841   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1842   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1843    
1844   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1845      dev = line->elements[1].item;      dev = line->elements[1].item;
1846   } else {   } else {
1847              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1848      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */       * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1849      line = entry->lines;       */
1850        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1851    
1852              /* failed to find one */              /* failed to find one */
1853              if (!line) return 0;              if (!line) {
1854     notSuitablePrintf(entry, 0, "no line found\n");
1855     return 0;
1856                }
1857    
1858      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1859          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1860      if (i < line->numElements)      if (i < line->numElements)
1861          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1862      else {      else {
1863     notSuitablePrintf(entry, 0, "no root= entry found\n");
1864   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1865          return 0;          return 0;
1866              }              }
1867   }   }
1868      }      }
1869    
1870      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1871   dev += 6;      if (!getpathbyspec(dev)) {
1872            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1873   /* check which device has this label */          return 0;
1874   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1875   if (!dev) return 0;   dev = getpathbyspec(dev);
1876    
1877        rootdev = findDiskForRoot();
1878        if (!rootdev) {
1879            notSuitablePrintf(entry, 0, "can't find root device\n");
1880     return 0;
1881      }      }
1882    
1883      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1884   if (stat(dev, &sb))          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1885      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1886      } else {          free(rootdev);
1887   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1888   if (*end) return 0;      }
1889    
1890        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1891            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1892     getuuidbydev(rootdev), getuuidbydev(dev));
1893     free(rootdev);
1894            return 0;
1895      }      }
     stat("/", &sb2);  
1896    
1897      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1898        notSuitablePrintf(entry, 1, "\n");
1899    
1900      return 1;      return 1;
1901  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1939  struct singleEntry * findEntryByPath(str
1939   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1940   if (!entry) return NULL;   if (!entry) return NULL;
1941    
1942   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1943   if (!line) return NULL;   if (!line) return NULL;
1944    
1945   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1977  struct singleEntry * findEntryByPath(str
1977    
1978   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1979      prefix = "";      prefix = "";
1980      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1981      kernel += 6;      kernel += 6;
1982   }   }
1983    
1984   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1985      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1986    
1987        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1988    
1989      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1990                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1991          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
1992                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1993                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1994                      break;   else if (checkType & LT_KERNEL)
1995              }      ct = checkType | LT_KERNEL_EFI;
1996                 line = getLineByType(ct, line);
1997              /* have to check multiboot lines too */   if (!line)
1998              if (entry->multiboot) {      break;  /* not found in this entry */
1999                  while (line && line->type != LT_MBMODULE) line = line->next;  
2000                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
2001                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
2002                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
2003                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
2004                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
2005                          break;   kernel + strlen(prefix)))
2006                  }   break;
2007              }   }
2008     if(line->type == LT_MENUENTRY &&
2009     !strcmp(line->elements[1].item, kernel))
2010        break;
2011        }
2012    
2013      i++;      /* make sure this entry has a kernel identifier; this skips
2014         * non-Linux boot entries (could find netbsd etc, though, which is
2015         * unfortunate)
2016         */
2017        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
2018     break; /* found 'im! */
2019   }   }
2020    
2021   if (index) *index = i;   if (index) *index = i;
2022      }      }
2023    
2024      if (!entry) return NULL;      return entry;
2025    }
2026    
2027      /* make sure this entry has a kernel identifier; this skips non-Linux  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2028         boot entries (could find netbsd etc, though, which is unfortunate) */        int * index) {
2029      line = entry->lines;      struct singleEntry * entry;
2030      while (line && line->type != LT_KERNEL) line = line->next;      struct singleLine * line;
2031      if (!line) {      int i;
2032   if (!index) index = &i;      char * newtitle;
2033   (*index)++;  
2034   return findEntryByPath(config, kernel, prefix, index);      for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2035     if (index && i < *index)
2036        continue;
2037     line = getLineByType(LT_TITLE, entry->lines);
2038     if (!line)
2039        line = getLineByType(LT_MENUENTRY, entry->lines);
2040     if (!line)
2041        continue;
2042     newtitle = grub2ExtractTitle(line);
2043     if (!newtitle)
2044        continue;
2045     if (!strcmp(title, newtitle))
2046        break;
2047      }      }
2048    
2049        if (!entry)
2050     return NULL;
2051    
2052        if (index)
2053     *index = i;
2054      return entry;      return entry;
2055  }  }
2056    
# Line 1147  struct singleEntry * findTemplate(struct Line 2076  struct singleEntry * findTemplate(struct
2076      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2077      int index;      int index;
2078    
2079      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2080     if (cfg->cfi->getEnv) {
2081        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2082        if (defTitle) {
2083     int index = 0;
2084     if (isnumber(defTitle)) {
2085        index = atoi(defTitle);
2086        entry = findEntryByIndex(cfg, index);
2087     } else {
2088        entry = findEntryByTitle(cfg, defTitle, &index);
2089     }
2090     if (entry)
2091        cfg->defaultImage = index;
2092        }
2093     }
2094        } else if (cfg->defaultImage > -1) {
2095   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2096   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2097      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1200  void markRemovedImage(struct grubConfig Line 2144  void markRemovedImage(struct grubConfig
2144        const char * prefix) {        const char * prefix) {
2145      struct singleEntry * entry;      struct singleEntry * entry;
2146    
2147      if (!image) return;      if (!image)
2148     return;
2149    
2150        /* check and see if we're removing the default image */
2151        if (isdigit(*image)) {
2152     entry = findEntryByPath(cfg, image, prefix, NULL);
2153     if(entry)
2154        entry->skip = 1;
2155     return;
2156        }
2157    
2158      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2159   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 2161  void markRemovedImage(struct grubConfig
2161    
2162  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2163       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2164       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2165      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2166      int i, j;      int i, j;
2167    
2168      if (newIsDefault) {      if (newIsDefault) {
2169   config->defaultImage = 0;   config->defaultImage = 0;
2170   return;   return;
2171        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2172     if (findEntryByIndex(config, index))
2173        config->defaultImage = index;
2174     else
2175        config->defaultImage = -1;
2176     return;
2177      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2178   i = 0;   i = 0;
2179   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 2186  void setDefaultImage(struct grubConfig *
2186    
2187      /* 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
2188         changes */         changes */
2189      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2190     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2191        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2192        return;        return;
2193    
# Line 1286  void displayEntry(struct singleEntry * e Line 2246  void displayEntry(struct singleEntry * e
2246      char * root = NULL;      char * root = NULL;
2247      int i;      int i;
2248    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2249      printf("index=%d\n", index);      printf("index=%d\n", index);
2250    
2251      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
2252        if (!line) {
2253            printf("non linux entry\n");
2254            return;
2255        }
2256    
2257        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2258     printf("kernel=%s\n", line->elements[1].item);
2259        else
2260     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2261    
2262      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2263   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2274  void displayEntry(struct singleEntry * e
2274   }   }
2275   printf("\"\n");   printf("\"\n");
2276      } else {      } else {
2277   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2278   if (line) {   if (line) {
2279      char * s;      char * s;
2280    
# Line 1334  void displayEntry(struct singleEntry * e Line 2298  void displayEntry(struct singleEntry * e
2298      }      }
2299    
2300      if (!root) {      if (!root) {
2301   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2302   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2303      root=line->elements[1].item;      root=line->elements[1].item;
2304      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2313  void displayEntry(struct singleEntry * e
2313   printf("root=%s\n", s);   printf("root=%s\n", s);
2314      }      }
2315    
2316      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2317    
2318      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2319   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2320        printf("initrd=");
2321     else
2322        printf("initrd=%s", prefix);
2323    
2324   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2325      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2326   printf("\n");   printf("\n");
2327      }      }
2328    
2329        line = getLineByType(LT_TITLE, entry->lines);
2330        if (line) {
2331     printf("title=%s\n", line->elements[1].item);
2332        } else {
2333     char * title;
2334     line = getLineByType(LT_MENUENTRY, entry->lines);
2335     title = grub2ExtractTitle(line);
2336     if (title)
2337        printf("title=%s\n", title);
2338        }
2339    }
2340    
2341    int isSuseSystem(void) {
2342        const char * path;
2343        const static char default_path[] = "/etc/SuSE-release";
2344    
2345        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2346     path = default_path;
2347    
2348        if (!access(path, R_OK))
2349     return 1;
2350        return 0;
2351    }
2352    
2353    int isSuseGrubConf(const char * path) {
2354        FILE * grubConf;
2355        char * line = NULL;
2356        size_t len = 0, res = 0;
2357    
2358        grubConf = fopen(path, "r");
2359        if (!grubConf) {
2360            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2361     return 0;
2362        }
2363    
2364        while ((res = getline(&line, &len, grubConf)) != -1) {
2365     if (!strncmp(line, "setup", 5)) {
2366        fclose(grubConf);
2367        free(line);
2368        return 1;
2369     }
2370        }
2371    
2372        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2373          path);
2374    
2375        fclose(grubConf);
2376        free(line);
2377        return 0;
2378    }
2379    
2380    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2381        FILE * grubConf;
2382        char * line = NULL;
2383        size_t res = 0, len = 0;
2384    
2385        if (!path) return 1;
2386        if (!lbaPtr) return 1;
2387    
2388        grubConf = fopen(path, "r");
2389        if (!grubConf) return 1;
2390    
2391        while ((res = getline(&line, &len, grubConf)) != -1) {
2392     if (line[res - 1] == '\n')
2393        line[res - 1] = '\0';
2394     else if (len > res)
2395        line[res] = '\0';
2396     else {
2397        line = realloc(line, res + 1);
2398        line[res] = '\0';
2399     }
2400    
2401     if (!strncmp(line, "setup", 5)) {
2402        if (strstr(line, "--force-lba")) {
2403            *lbaPtr = 1;
2404        } else {
2405            *lbaPtr = 0;
2406        }
2407        dbgPrintf("lba: %i\n", *lbaPtr);
2408        break;
2409     }
2410        }
2411    
2412        free(line);
2413        fclose(grubConf);
2414        return 0;
2415    }
2416    
2417    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2418        FILE * grubConf;
2419        char * line = NULL;
2420        size_t res = 0, len = 0;
2421        char * lastParamPtr = NULL;
2422        char * secLastParamPtr = NULL;
2423        char installDeviceNumber = '\0';
2424        char * bounds = NULL;
2425    
2426        if (!path) return 1;
2427        if (!devicePtr) return 1;
2428    
2429        grubConf = fopen(path, "r");
2430        if (!grubConf) return 1;
2431    
2432        while ((res = getline(&line, &len, grubConf)) != -1) {
2433     if (strncmp(line, "setup", 5))
2434        continue;
2435    
2436     if (line[res - 1] == '\n')
2437        line[res - 1] = '\0';
2438     else if (len > res)
2439        line[res] = '\0';
2440     else {
2441        line = realloc(line, res + 1);
2442        line[res] = '\0';
2443     }
2444    
2445     lastParamPtr = bounds = line + res;
2446    
2447     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2448     while (!isspace(*lastParamPtr))
2449        lastParamPtr--;
2450     lastParamPtr++;
2451    
2452     secLastParamPtr = lastParamPtr - 2;
2453     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2454    
2455     if (lastParamPtr + 3 > bounds) {
2456        dbgPrintf("lastParamPtr going over boundary");
2457        fclose(grubConf);
2458        free(line);
2459        return 1;
2460     }
2461     if (!strncmp(lastParamPtr, "(hd", 3))
2462        lastParamPtr += 3;
2463     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2464    
2465     /*
2466     * Second last parameter will decide wether last parameter is
2467     * an IMAGE_DEVICE or INSTALL_DEVICE
2468     */
2469     while (!isspace(*secLastParamPtr))
2470        secLastParamPtr--;
2471     secLastParamPtr++;
2472    
2473     if (secLastParamPtr + 3 > bounds) {
2474        dbgPrintf("secLastParamPtr going over boundary");
2475        fclose(grubConf);
2476        free(line);
2477        return 1;
2478     }
2479     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2480     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2481        secLastParamPtr += 3;
2482        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2483        installDeviceNumber = *secLastParamPtr;
2484     } else {
2485        installDeviceNumber = *lastParamPtr;
2486     }
2487    
2488     *devicePtr = malloc(6);
2489     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2490     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2491     fclose(grubConf);
2492     free(line);
2493     return 0;
2494        }
2495    
2496        free(line);
2497        fclose(grubConf);
2498        return 1;
2499    }
2500    
2501    int grubGetBootFromDeviceMap(const char * device,
2502         char ** bootPtr) {
2503        FILE * deviceMap;
2504        char * line = NULL;
2505        size_t res = 0, len = 0;
2506        char * devicePtr;
2507        char * bounds = NULL;
2508        const char * path;
2509        const static char default_path[] = "/boot/grub/device.map";
2510    
2511        if (!device) return 1;
2512        if (!bootPtr) return 1;
2513    
2514        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2515     path = default_path;
2516    
2517        dbgPrintf("opening grub device.map file from: %s\n", path);
2518        deviceMap = fopen(path, "r");
2519        if (!deviceMap)
2520     return 1;
2521    
2522        while ((res = getline(&line, &len, deviceMap)) != -1) {
2523            if (!strncmp(line, "#", 1))
2524        continue;
2525    
2526     if (line[res - 1] == '\n')
2527        line[res - 1] = '\0';
2528     else if (len > res)
2529        line[res] = '\0';
2530     else {
2531        line = realloc(line, res + 1);
2532        line[res] = '\0';
2533     }
2534    
2535     devicePtr = line;
2536     bounds = line + res;
2537    
2538     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2539        devicePtr++;
2540     dbgPrintf("device: %s\n", devicePtr);
2541    
2542     if (!strncmp(devicePtr, device, strlen(device))) {
2543        devicePtr += strlen(device);
2544        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2545            devicePtr++;
2546    
2547        *bootPtr = strdup(devicePtr);
2548        break;
2549     }
2550        }
2551    
2552        free(line);
2553        fclose(deviceMap);
2554        return 0;
2555    }
2556    
2557    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2558        char * grubDevice;
2559    
2560        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2561     dbgPrintf("error looking for grub installation device\n");
2562        else
2563     dbgPrintf("grubby installation device: %s\n", grubDevice);
2564    
2565        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2566     dbgPrintf("error looking for grub boot device\n");
2567        else
2568     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2569    
2570        free(grubDevice);
2571        return 0;
2572    }
2573    
2574    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2575        /*
2576         * This SuSE grub configuration file at this location is not your average
2577         * grub configuration file, but instead the grub commands used to setup
2578         * grub on that system.
2579         */
2580        const char * path;
2581        const static char default_path[] = "/etc/grub.conf";
2582    
2583        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2584     path = default_path;
2585    
2586        if (!isSuseGrubConf(path)) return 1;
2587    
2588        if (lbaPtr) {
2589            *lbaPtr = 0;
2590            if (suseGrubConfGetLba(path, lbaPtr))
2591                return 1;
2592        }
2593    
2594        if (bootPtr) {
2595            *bootPtr = NULL;
2596            suseGrubConfGetBoot(path, bootPtr);
2597        }
2598    
2599        return 0;
2600  }  }
2601    
2602  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2606  int parseSysconfigGrub(int * lbaPtr, cha
2606      char * start;      char * start;
2607      char * param;      char * param;
2608    
2609      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2610      if (!in) return 1;      if (!in) return 1;
2611    
2612      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2647  int parseSysconfigGrub(int * lbaPtr, cha
2647  }  }
2648    
2649  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2650      char * boot;      char * boot = NULL;
2651      int lba;      int lba;
2652    
2653      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2654   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2655   if (boot) printf("boot=%s\n", boot);      free(boot);
2656        return;
2657     }
2658        } else {
2659            if (parseSysconfigGrub(&lba, &boot)) {
2660        free(boot);
2661        return;
2662     }
2663        }
2664    
2665        if (lba) printf("lba\n");
2666        if (boot) {
2667     printf("boot=%s\n", boot);
2668     free(boot);
2669      }      }
2670  }  }
2671    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2681  int displayInfo(struct grubConfig * conf
2681   return 1;   return 1;
2682      }      }
2683    
2684      /* 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
2685         be a better way */         be a better way */
2686      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2687   dumpSysconfigGrub();   dumpSysconfigGrub();
2688      } else {      } else {
2689   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2690   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2691      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2692   }   }
2693    
2694   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2695   if (line) printf("lba\n");   if (line) printf("lba\n");
2696      }      }
2697    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2706  int displayInfo(struct grubConfig * conf
2706      return 0;      return 0;
2707  }  }
2708    
2709    struct singleLine * addLineTmpl(struct singleEntry * entry,
2710     struct singleLine * tmplLine,
2711     struct singleLine * prevLine,
2712     const char * val,
2713     struct configFileInfo * cfi)
2714    {
2715        struct singleLine * newLine = lineDup(tmplLine);
2716    
2717        if (isEfi && cfi == &grub2ConfigType) {
2718     enum lineType_e old = newLine->type;
2719     newLine->type = preferredLineType(newLine->type, cfi);
2720     if (old != newLine->type)
2721        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2722        }
2723    
2724        if (val) {
2725     /* override the inherited value with our own.
2726     * This is a little weak because it only applies to elements[1]
2727     */
2728     if (newLine->numElements > 1)
2729        removeElement(newLine, 1);
2730     insertElement(newLine, val, 1, cfi);
2731    
2732     /* but try to keep the rootspec from the template... sigh */
2733     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2734        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2735        if (rootspec != NULL) {
2736     free(newLine->elements[1].item);
2737     newLine->elements[1].item =
2738        sdupprintf("%s%s", rootspec, val);
2739        }
2740     }
2741        }
2742    
2743        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2744          newLine->elements[0].item : "");
2745    
2746        if (!entry->lines) {
2747     /* first one on the list */
2748     entry->lines = newLine;
2749        } else if (prevLine) {
2750     /* add after prevLine */
2751     newLine->next = prevLine->next;
2752     prevLine->next = newLine;
2753        }
2754    
2755        return newLine;
2756    }
2757    
2758  /* val may be NULL */  /* val may be NULL */
2759  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2760       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2761       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2762       char * val) {       const char * val) {
2763      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2764      int i;      struct keywordTypes * kw;
2765        struct singleLine tmpl;
2766    
2767      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2768   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2769      if (type != LT_TITLE || !cfi->titleBracketed)       */
2770          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2771     /* we're doing a bracketed title (zipl) */
2772     tmpl.type = type;
2773     tmpl.numElements = 1;
2774     tmpl.elements = alloca(sizeof(*tmpl.elements));
2775     tmpl.elements[0].item = alloca(strlen(val)+3);
2776     sprintf(tmpl.elements[0].item, "[%s]", val);
2777     tmpl.elements[0].indent = "";
2778     val = NULL;
2779        } else if (type == LT_MENUENTRY) {
2780     char *lineend = "--class gnu-linux --class gnu --class os {";
2781     if (!val) {
2782        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2783        abort();
2784     }
2785     kw = getKeywordByType(type, cfi);
2786     if (!kw) {
2787        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2788        abort();
2789     }
2790     tmpl.indent = "";
2791     tmpl.type = type;
2792     tmpl.numElements = 3;
2793     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2794     tmpl.elements[0].item = kw->key;
2795     tmpl.elements[0].indent = alloca(2);
2796     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2797     tmpl.elements[1].item = (char *)val;
2798     tmpl.elements[1].indent = alloca(2);
2799     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2800     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2801     strcpy(tmpl.elements[2].item, lineend);
2802     tmpl.elements[2].indent = "";
2803        } else {
2804     kw = getKeywordByType(type, cfi);
2805     if (!kw) {
2806        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2807        abort();
2808     }
2809     tmpl.type = type;
2810     tmpl.numElements = val ? 2 : 1;
2811     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2812     tmpl.elements[0].item = kw->key;
2813     tmpl.elements[0].indent = alloca(2);
2814     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2815     if (val) {
2816        tmpl.elements[1].item = (char *)val;
2817        tmpl.elements[1].indent = "";
2818     }
2819        }
2820    
2821      /* 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
2822         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2823         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
2824         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2825         differently from the rest) */         differently from the rest) */
2826      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2827   line = entry->lines;   if (line->numElements) prev = line;
2828   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2829   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;  
2830      }      }
2831    
2832      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2833          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2834          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2835          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2836          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2837          line->elements[0].indent = malloc(2);   else
2838          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2839          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2840             if (menuEntry)
2841          if (val) {      tmpl.indent = "\t";
2842              line->elements[1].item = val;   else if (prev == entry->lines)
2843              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2844          }   else
2845      } 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("");  
2846      }      }
2847    
2848      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2849  }  }
2850    
2851  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2870  void removeLine(struct singleEntry * ent
2870      free(line);      free(line);
2871  }  }
2872    
2873    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2874    {
2875        struct singleLine newLine = {
2876     .indent = tmplLine->indent,
2877     .type = tmplLine->type,
2878     .next = tmplLine->next,
2879        };
2880        int firstQuotedItem = -1;
2881        int quoteLen = 0;
2882        int j;
2883        int element = 0;
2884        char *c;
2885    
2886        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2887        strcpy(c, tmplLine->elements[0].item);
2888        insertElement(&newLine, c, element++, cfi);
2889        free(c);
2890        c = NULL;
2891    
2892        for (j = 1; j < tmplLine->numElements; j++) {
2893     if (firstQuotedItem == -1) {
2894        quoteLen += strlen(tmplLine->elements[j].item);
2895        
2896        if (isquote(tmplLine->elements[j].item[0])) {
2897     firstQuotedItem = j;
2898            quoteLen += strlen(tmplLine->elements[j].indent);
2899        } else {
2900     c = malloc(quoteLen + 1);
2901     strcpy(c, tmplLine->elements[j].item);
2902     insertElement(&newLine, c, element++, cfi);
2903     free(c);
2904     quoteLen = 0;
2905        }
2906     } else {
2907        int itemlen = strlen(tmplLine->elements[j].item);
2908        quoteLen += itemlen;
2909        quoteLen += strlen(tmplLine->elements[j].indent);
2910        
2911        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2912     c = malloc(quoteLen + 1);
2913     c[0] = '\0';
2914     for (int i = firstQuotedItem; i < j+1; i++) {
2915        strcat(c, tmplLine->elements[i].item);
2916        strcat(c, tmplLine->elements[i].indent);
2917     }
2918     insertElement(&newLine, c, element++, cfi);
2919     free(c);
2920    
2921     firstQuotedItem = -1;
2922     quoteLen = 0;
2923        }
2924     }
2925        }
2926        while (tmplLine->numElements)
2927     removeElement(tmplLine, 0);
2928        if (tmplLine->elements)
2929     free(tmplLine->elements);
2930    
2931        tmplLine->numElements = newLine.numElements;
2932        tmplLine->elements = newLine.elements;
2933    }
2934    
2935    static void insertElement(struct singleLine * line,
2936      const char * item, int insertHere,
2937      struct configFileInfo * cfi)
2938    {
2939        struct keywordTypes * kw;
2940        char indent[2] = "";
2941    
2942        /* sanity check */
2943        if (insertHere > line->numElements) {
2944     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2945      insertHere, line->numElements);
2946     insertHere = line->numElements;
2947        }
2948    
2949        line->elements = realloc(line->elements, (line->numElements + 1) *
2950         sizeof(*line->elements));
2951        memmove(&line->elements[insertHere+1],
2952        &line->elements[insertHere],
2953        (line->numElements - insertHere) *
2954        sizeof(*line->elements));
2955        line->elements[insertHere].item = strdup(item);
2956    
2957        kw = getKeywordByType(line->type, cfi);
2958    
2959        if (line->numElements == 0) {
2960     indent[0] = '\0';
2961        } else if (insertHere == 0) {
2962     indent[0] = kw->nextChar;
2963        } else if (kw->separatorChar != '\0') {
2964     indent[0] = kw->separatorChar;
2965        } else {
2966     indent[0] = ' ';
2967        }
2968    
2969        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2970     /* move the end-of-line forward */
2971     line->elements[insertHere].indent =
2972        line->elements[insertHere-1].indent;
2973     line->elements[insertHere-1].indent = strdup(indent);
2974        } else {
2975     line->elements[insertHere].indent = strdup(indent);
2976        }
2977    
2978        line->numElements++;
2979    
2980        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2981          line->elements[0].item,
2982          line->elements[insertHere].item,
2983          line->elements[insertHere].indent,
2984          insertHere);
2985    }
2986    
2987    static void removeElement(struct singleLine * line, int removeHere) {
2988        int i;
2989    
2990        /* sanity check */
2991        if (removeHere >= line->numElements) return;
2992    
2993        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2994          removeHere, line->elements[removeHere].item);
2995    
2996        free(line->elements[removeHere].item);
2997    
2998        if (removeHere > 1) {
2999     /* previous argument gets this argument's post-indentation */
3000     free(line->elements[removeHere-1].indent);
3001     line->elements[removeHere-1].indent =
3002        line->elements[removeHere].indent;
3003        } else {
3004     free(line->elements[removeHere].indent);
3005        }
3006    
3007        /* now collapse the array, but don't bother to realloc smaller */
3008        for (i = removeHere; i < line->numElements - 1; i++)
3009     line->elements[i] = line->elements[i + 1];
3010    
3011        line->numElements--;
3012    }
3013    
3014  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
3015      char * first, * second;      char * first, * second;
3016      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 3033  int updateActualImage(struct grubConfig
3033      struct singleEntry * entry;      struct singleEntry * entry;
3034      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
3035      int index = 0;      int index = 0;
3036      int i, j, k;      int i, k;
3037      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
3038      const char ** arg;      const char ** arg;
3039      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
3040      int firstElement;      int firstElement;
3041      int *usedElements, *usedArgs;      int *usedElements;
3042        int doreplace;
3043    
3044      if (!image) return 0;      if (!image) return 0;
3045    
# Line 1609  int updateActualImage(struct grubConfig Line 3066  int updateActualImage(struct grubConfig
3066   }   }
3067      }      }
3068    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
3069    
3070      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
3071   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
3072    
3073      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3074   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
3075    
3076      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
3077    
3078      k = 0;   if (multibootArgs && !entry->multiboot)
3079      for (arg = newArgs; *arg; arg++)      continue;
3080          k++;  
3081      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
3082     * LT_KERNELARGS, use that.  Otherwise use
3083     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
3084     */
3085     if (useKernelArgs) {
3086        line = getLineByType(LT_KERNELARGS, entry->lines);
3087        if (!line) {
3088     /* no LT_KERNELARGS, need to add it */
3089     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
3090           cfg->secondaryIndent, NULL);
3091        }
3092        firstElement = 1;
3093    
3094      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
3095   index++;      line = getLineByType(LT_HYPER, entry->lines);
3096        if (!line) {
3097     /* a multiboot entry without LT_HYPER? */
3098     continue;
3099        }
3100        firstElement = 2;
3101    
3102   line = entry->lines;   } else {
3103   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
3104   if (!line) continue;      if (!line) {
3105   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3106     continue;
3107          if (entry->multiboot && !multibootArgs) {      }
3108              /* 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;  
3109   }   }
3110    
3111   if (!line && useKernelArgs) {   /* handle the elilo case which does:
3112      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
3113      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
3114     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
3115        /* this is a multiboot entry, make sure there's
3116         * -- on the args line
3117         */
3118        for (i = firstElement; i < line->numElements; i++) {
3119     if (!strcmp(line->elements[i].item, "--"))
3120        break;
3121        }
3122        if (i == line->numElements) {
3123     /* assume all existing args are kernel args,
3124     * prepend -- to make it official
3125     */
3126     insertElement(line, "--", firstElement, cfg->cfi);
3127     i = firstElement;
3128        }
3129        if (!multibootArgs) {
3130     /* kernel args start after the -- */
3131     firstElement = i + 1;
3132        }
3133     } else if (cfg->cfi->mbConcatArgs) {
3134        /* this is a non-multiboot entry, remove hyper args */
3135        for (i = firstElement; i < line->numElements; i++) {
3136     if (!strcmp(line->elements[i].item, "--"))
3137        break;
3138        }
3139        if (i < line->numElements) {
3140     /* remove args up to -- */
3141     while (strcmp(line->elements[firstElement].item, "--"))
3142        removeElement(line, firstElement);
3143     /* remove -- */
3144     removeElement(line, firstElement);
3145        }
3146   }   }
3147    
3148          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
3149    
3150          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
3151   for (arg = newArgs; *arg; arg++) {  
3152              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
3153      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
3154     if (multibootArgs && cfg->cfi->mbConcatArgs &&
3155        !strcmp(line->elements[i].item, "--"))
3156     {
3157        /* reached the end of hyper args, insert here */
3158        doreplace = 0;
3159        break;  
3160     }
3161                  if (usedElements[i])                  if (usedElements[i])
3162                      continue;                      continue;
3163   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3164                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3165      break;      break;
3166                  }                  }
3167              }              }
     chptr = strchr(*arg, '=');  
3168    
3169      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
3170   /* replace */   /* direct replacement */
3171   free(line->elements[i].item);   free(line->elements[i].item);
3172   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("");  
  }  
3173    
3174   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
3175   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
3176      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
3177   /* append */   if (rootLine) {
3178   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
3179   (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(" ");  
3180   } else {   } else {
3181      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
3182         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
3183   }   }
3184        }
3185    
3186   line->numElements++;      else {
3187     /* insert/append */
3188     insertElement(line, *arg, i, cfg->cfi);
3189     usedElements = realloc(usedElements, line->numElements *
3190           sizeof(*usedElements));
3191     memmove(&usedElements[i + 1], &usedElements[i],
3192     line->numElements - i - 1);
3193     usedElements[i] = 1;
3194    
3195   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
3196     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
3197     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
3198   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
3199      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
3200      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
3201   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
3202   }   }
3203      }      }
             k++;  
3204   }   }
3205    
3206          free(usedElements);          free(usedElements);
3207    
  /* 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? */  
3208   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
3209      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3210   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3211        !strcmp(line->elements[i].item, "--"))
3212        /* reached the end of hyper args, stop here */
3213        break;
3214     if (!argMatch(line->elements[i].item, *arg)) {
3215        removeElement(line, i);
3216      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;  
3217   }   }
3218        }
3219   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3220        if (useRoot && !strncmp(*arg, "root=", 5)) {
3221   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3222      line->elements[j - 1] = line->elements[j];   if (rootLine)
3223        removeLine(entry, rootLine);
  line->numElements--;  
3224      }      }
3225   }   }
3226    
# Line 1760  int updateActualImage(struct grubConfig Line 3231  int updateActualImage(struct grubConfig
3231   }   }
3232      }      }
3233    
     free(usedArgs);  
3234      free(newArgs);      free(newArgs);
3235      free(oldArgs);      free(oldArgs);
3236    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3256  int updateImage(struct grubConfig * cfg,
3256      return rc;      return rc;
3257  }  }
3258    
3259    int updateInitrd(struct grubConfig * cfg, const char * image,
3260                     const char * prefix, const char * initrd) {
3261        struct singleEntry * entry;
3262        struct singleLine * line, * kernelLine, *endLine = NULL;
3263        int index = 0;
3264    
3265        if (!image) return 0;
3266    
3267        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3268            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3269            if (!kernelLine) continue;
3270    
3271            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3272            if (line)
3273                removeLine(entry, line);
3274            if (prefix) {
3275                int prefixLen = strlen(prefix);
3276                if (!strncmp(initrd, prefix, prefixLen))
3277                    initrd += prefixLen;
3278            }
3279     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3280     if (endLine)
3281        removeLine(entry, endLine);
3282            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3283     kernelLine->indent, initrd);
3284            if (!line)
3285        return 1;
3286     if (endLine) {
3287        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3288                if (!line)
3289     return 1;
3290     }
3291    
3292            break;
3293        }
3294    
3295        return 0;
3296    }
3297    
3298  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3299      int fd;      int fd;
3300      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3318  int checkDeviceBootloader(const char * d
3318      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3319   return 0;   return 0;
3320    
3321      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3322   offset = boot[2] + 2;   offset = boot[2] + 2;
3323      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3324   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3325      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3326   offset = boot[1] + 2;        offset = boot[1] + 2;
3327            /*
3328     * it looks like grub, when copying stage1 into the mbr, patches stage1
3329     * right after the JMP location, replacing other instructions such as
3330     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3331     * different bytes.
3332     */
3333          if ((bootSect[offset + 1] == NOOP_OPCODE)
3334      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3335     offset = offset + 3;
3336          }
3337      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3338   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3339      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3475  int checkForLilo(struct grubConfig * con
3475      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3476  }  }
3477    
3478    int checkForGrub2(struct grubConfig * config) {
3479        if (!access("/etc/grub.d/", R_OK))
3480     return 2;
3481    
3482        return 1;
3483    }
3484    
3485  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3486      int fd;      int fd;
3487      unsigned char bootSect[512];      unsigned char bootSect[512];
3488      char * boot;      char * boot;
3489        int onSuse = isSuseSystem();
3490    
3491      if (parseSysconfigGrub(NULL, &boot))  
3492   return 0;      if (onSuse) {
3493     if (parseSuseGrubConf(NULL, &boot))
3494        return 0;
3495        } else {
3496     if (parseSysconfigGrub(NULL, &boot))
3497        return 0;
3498        }
3499    
3500      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3501      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3509  int checkForGrub(struct grubConfig * con
3509      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3510   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3511   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3512     close(fd);
3513   return 1;   return 1;
3514      }      }
3515      close(fd);      close(fd);
3516    
3517        /* The more elaborate checks do not work on SuSE. The checks done
3518         * seem to be reasonble (at least for now), so just return success
3519         */
3520        if (onSuse)
3521     return 2;
3522    
3523      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3524  }  }
3525    
3526    int checkForExtLinux(struct grubConfig * config) {
3527        int fd;
3528        unsigned char bootSect[512];
3529        char * boot;
3530        char executable[] = "/boot/extlinux/extlinux";
3531    
3532        printf("entered: checkForExtLinux()\n");
3533    
3534        if (parseSysconfigGrub(NULL, &boot))
3535     return 0;
3536    
3537        /* assume grub is not installed -- not an error condition */
3538        if (!boot)
3539     return 0;
3540    
3541        fd = open(executable, O_RDONLY);
3542        if (fd < 0)
3543     /* this doesn't exist if grub hasn't been installed */
3544     return 0;
3545    
3546        if (read(fd, bootSect, 512) != 512) {
3547     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3548     executable, strerror(errno));
3549     return 1;
3550        }
3551        close(fd);
3552    
3553        return checkDeviceBootloader(boot, bootSect);
3554    }
3555    
3556    int checkForYaboot(struct grubConfig * config) {
3557        /*
3558         * This is a simplistic check that we consider good enough for own puporses
3559         *
3560         * If we were to properly check if yaboot is *installed* we'd need to:
3561         * 1) get the system boot device (LT_BOOT)
3562         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3563         *    the content on the boot device
3564         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3565         * 4) check again if binary and boot device contents match
3566         */
3567        if (!access("/etc/yaboot.conf", R_OK))
3568     return 2;
3569    
3570        return 1;
3571    }
3572    
3573    int checkForElilo(struct grubConfig * config) {
3574        if (!access("/etc/elilo.conf", R_OK))
3575     return 2;
3576    
3577        return 1;
3578    }
3579    
3580  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3581      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3582    
# Line 1994  static char * getRootSpecifier(char * st Line 3588  static char * getRootSpecifier(char * st
3588      return rootspec;      return rootspec;
3589  }  }
3590    
3591    static char * getInitrdVal(struct grubConfig * config,
3592       const char * prefix, struct singleLine *tmplLine,
3593       const char * newKernelInitrd,
3594       const char ** extraInitrds, int extraInitrdCount)
3595    {
3596        char *initrdVal, *end;
3597        int i;
3598        size_t totalSize;
3599        size_t prefixLen;
3600        char separatorChar;
3601    
3602        prefixLen = strlen(prefix);
3603        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3604    
3605        for (i = 0; i < extraInitrdCount; i++) {
3606     totalSize += sizeof(separatorChar);
3607     totalSize += strlen(extraInitrds[i]) - prefixLen;
3608        }
3609    
3610        initrdVal = end = malloc(totalSize);
3611    
3612        end = stpcpy (end, newKernelInitrd + prefixLen);
3613    
3614        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3615        for (i = 0; i < extraInitrdCount; i++) {
3616     const char *extraInitrd;
3617     int j;
3618    
3619     extraInitrd = extraInitrds[i] + prefixLen;
3620     /* Don't add entries that are already there */
3621     if (tmplLine != NULL) {
3622        for (j = 2; j < tmplLine->numElements; j++)
3623     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3624        break;
3625    
3626        if (j != tmplLine->numElements)
3627     continue;
3628     }
3629    
3630     *end++ = separatorChar;
3631     end = stpcpy(end, extraInitrd);
3632        }
3633    
3634        return initrdVal;
3635    }
3636    
3637  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3638           const char * prefix,           const char * prefix,
3639   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3640   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3641                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3642                     const char * newMBKernel, const char * newMBKernelArgs) {
3643      struct singleEntry * new;      struct singleEntry * new;
3644      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3645      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3646      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3647    
3648      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3649    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3673  int addNewKernel(struct grubConfig * con
3673      config->entries = new;      config->entries = new;
3674    
3675      /* copy/update from the template */      /* copy/update from the template */
3676      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3677        if (newKernelInitrd)
3678     needs |= NEED_INITRD;
3679      if (newMBKernel) {      if (newMBKernel) {
3680          needs |= KERNEL_MB;          needs |= NEED_MB;
3681          new->multiboot = 1;          new->multiboot = 1;
3682      }      }
3683    
3684      if (template) {      if (template) {
3685   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3686      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3687      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3688   indent = tmplLine->indent;   {
3689        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3690    
3691      /* skip comments */      /* skip comments */
3692      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3693      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3694      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3695    
3696      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3697      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3698        /* it's not a multiboot template and this is the kernel
3699              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3700                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3701                  struct singleLine *l;       */
3702                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3703     /* insert the hypervisor first */
3704                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3705                                    config->secondaryIndent,    tmplLine->indent,
3706                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3707                     /* set up for adding the kernel line */
3708                  tmplLine = lastLine;   free(tmplLine->indent);
3709                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3710                      new->lines = l;   needs &= ~NEED_MB;
3711                  } else {      }
3712                      newLine->next = l;      if (needs & NEED_KERNEL) {
3713                      newLine = l;   /* use addLineTmpl to preserve line elements,
3714                  }   * otherwise we could just call addLine.  Unfortunately
3715                  continue;   * this means making some changes to the template
3716              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3717                         template->multiboot && !new->multiboot) {   * change below.
3718                  continue; /* don't need multiboot kernel here */   */
3719              }   struct keywordTypes * mbm_kw =
3720        getKeywordByType(LT_MBMODULE, config->cfi);
3721      if (!new->lines) {   if (mbm_kw) {
3722   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3723   new->lines = newLine;      free(tmplLine->elements[0].item);
3724      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3725   newLine->next = malloc(sizeof(*newLine));   }
3726   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3727      }        newKernelPath + strlen(prefix), config->cfi);
3728     needs &= ~NEED_KERNEL;
3729        }
3730        if (needs & NEED_MB) { /* !mbHyperFirst */
3731     newLine = addLine(new, config->cfi, LT_HYPER,
3732      config->secondaryIndent,
3733      newMBKernel + strlen(prefix));
3734     needs &= ~NEED_MB;
3735        }
3736     } else if (needs & NEED_KERNEL) {
3737        newLine = addLineTmpl(new, tmplLine, newLine,
3738      newKernelPath + strlen(prefix), config->cfi);
3739        needs &= ~NEED_KERNEL;
3740     }
3741    
3742        } else if (tmplLine->type == LT_HYPER &&
3743           tmplLine->numElements >= 2) {
3744     if (needs & NEED_MB) {
3745        newLine = addLineTmpl(new, tmplLine, newLine,
3746      newMBKernel + strlen(prefix), config->cfi);
3747        needs &= ~NEED_MB;
3748     }
3749    
3750      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3751      newLine->next = NULL;         tmplLine->numElements >= 2) {
3752      newLine->type = tmplLine->type;   if (new->multiboot) {
3753      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3754      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3755      newLine->numElements);        newKernelPath +
3756      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3757   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3758   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3759   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3760      }   char *initrdVal;
3761     initrdVal = getInitrdVal(config, prefix, tmplLine,
3762              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3763      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3764                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3765                  if (!template->multiboot) {        initrdVal, config->cfi);
3766                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3767                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3768                  } else {      }
3769                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3770                      repl = newMBKernel;      /* template is multi but new is not,
3771                  }       * insert the kernel in the first module slot
3772                  if (new->multiboot && !template->multiboot) {       */
3773                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3774                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3775                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3776                  }   strdup(getKeywordByType(tmplLine->type,
3777   free(newLine->elements[1].item);   config->cfi)->key);
3778                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3779                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3780                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3781                                                             rootspec,      needs &= ~NEED_KERNEL;
3782                                                             repl +   } else if (needs & NEED_INITRD) {
3783                                                             strlen(prefix));      char *initrdVal;
3784                  } else {      /* template is multi but new is not,
3785                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3786                                                         strlen(prefix));       */
3787                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3788              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3789                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3790                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3791                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3792                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3793                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3794                      newLine->type = LT_KERNEL;      free(initrdVal);
3795                  }      needs &= ~NEED_INITRD;
3796   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;  
3797    
3798   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3799      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3800      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3801        config->cfi->mbInitRdIsModule) {
3802        /* make sure we don't insert the module initrd
3803         * before the module kernel... if we don't do it here,
3804         * it will be inserted following the template.
3805         */
3806        if (!needs & NEED_KERNEL) {
3807     char *initrdVal;
3808    
3809     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3810     newLine = addLine(new, config->cfi, LT_MBMODULE,
3811      config->secondaryIndent,
3812      initrdVal);
3813     free(initrdVal);
3814     needs &= ~NEED_INITRD;
3815        }
3816     } else if (needs & NEED_INITRD) {
3817        char *initrdVal;
3818        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3819        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3820        free(initrdVal);
3821        needs &= ~NEED_INITRD;
3822   }   }
3823    
3824   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3825   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3826   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3827     char *nkt = malloc(strlen(newKernelTitle)+3);
3828     strcpy(nkt, "'");
3829     strcat(nkt, newKernelTitle);
3830     strcat(nkt, "'");
3831     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3832     free(nkt);
3833     needs &= ~NEED_TITLE;
3834      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3835                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3836                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3837                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3838                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3839                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3840                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3841                                             newLine->numElements);     config->cfi->titleBracketed) {
3842        /* addLineTmpl doesn't handle titleBracketed */
3843                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3844                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3845                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3846                  newLine->numElements = 1;   }
3847              }      } else if (tmplLine->type == LT_ECHO) {
3848        requote(tmplLine, config->cfi);
3849        static const char *prefix = "'Loading ";
3850        if (tmplLine->numElements > 1 &&
3851        strstr(tmplLine->elements[1].item, prefix) &&
3852        masterLine->next &&
3853        iskernel(masterLine->next->type)) {
3854     char *newTitle = malloc(strlen(prefix) +
3855     strlen(newKernelTitle) + 2);
3856    
3857     strcpy(newTitle, prefix);
3858     strcat(newTitle, newKernelTitle);
3859     strcat(newTitle, "'");
3860     newLine = addLine(new, config->cfi, LT_ECHO,
3861     tmplLine->indent, newTitle);
3862     free(newTitle);
3863        } else {
3864     /* pass through other lines from the template */
3865     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3866     config->cfi);
3867        }
3868        } else {
3869     /* pass through other lines from the template */
3870     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3871        }
3872   }   }
3873    
3874      } else {      } else {
3875   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3876      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3877     */
3878     switch (config->cfi->entryStart) {
3879        case LT_KERNEL:
3880        case LT_KERNEL_EFI:
3881     if (new->multiboot && config->cfi->mbHyperFirst) {
3882        /* fall through to LT_HYPER */
3883     } else {
3884        newLine = addLine(new, config->cfi,
3885              preferredLineType(LT_KERNEL, config->cfi),
3886          config->primaryIndent,
3887          newKernelPath + strlen(prefix));
3888        needs &= ~NEED_KERNEL;
3889        break;
3890     }
3891    
3892        case LT_HYPER:
3893     newLine = addLine(new, config->cfi, LT_HYPER,
3894      config->primaryIndent,
3895      newMBKernel + strlen(prefix));
3896     needs &= ~NEED_MB;
3897   break;   break;
         }  
3898    
3899   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3900      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3901       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3902       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3903      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3904       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3905      default:        config->primaryIndent, nkt);
3906                  /* zipl strikes again */   free(nkt);
3907                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3908                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3909                      chptr = newKernelTitle;   break;
3910                      type = LT_TITLE;      }
3911                      break;      case LT_TITLE:
3912                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3913                      abort();   char * templabel;
3914                  }   int x = 0, y = 0;
3915   }  
3916     templabel = strdup(newKernelTitle);
3917     while( templabel[x]){
3918     if( templabel[x] == ' ' ){
3919     y = x;
3920     while( templabel[y] ){
3921     templabel[y] = templabel[y+1];
3922     y++;
3923     }
3924     }
3925     x++;
3926     }
3927     newLine = addLine(new, config->cfi, LT_TITLE,
3928      config->primaryIndent, templabel);
3929     free(templabel);
3930     }else{
3931     newLine = addLine(new, config->cfi, LT_TITLE,
3932      config->primaryIndent, newKernelTitle);
3933     }
3934     needs &= ~NEED_TITLE;
3935     break;
3936    
3937   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3938   new->lines = newLine;   abort();
3939     }
3940      }      }
3941    
3942      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3943          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3944              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3945                                config->secondaryIndent,       */
3946                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3947          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3948              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3949                                config->secondaryIndent,    newKernelTitle);
3950                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3951          /* don't need to check for title as it's guaranteed to have been      }
3952           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3953           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3954          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3955              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3956                                config->secondaryIndent,   needs &= ~NEED_MB;
3957                                newKernelInitrd + strlen(prefix));      }
3958      } else {      if (needs & NEED_KERNEL) {
3959          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3960              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3961                                config->secondaryIndent,        config->cfi))
3962                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3963          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3964              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3965                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3966                                newKernelTitle);   needs &= ~NEED_KERNEL;
3967          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3968              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3969                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3970                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3971      newMBKernel + strlen(prefix));
3972     needs &= ~NEED_MB;
3973        }
3974        if (needs & NEED_INITRD) {
3975     char *initrdVal;
3976     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3977     newLine = addLine(new, config->cfi,
3978      (new->multiboot && getKeywordByType(LT_MBMODULE,
3979          config->cfi))
3980       ? LT_MBMODULE
3981       : preferredLineType(LT_INITRD, config->cfi),
3982      config->secondaryIndent,
3983      initrdVal);
3984     free(initrdVal);
3985     needs &= ~NEED_INITRD;
3986        }
3987        if (needs & NEED_END) {
3988     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3989     config->secondaryIndent, NULL);
3990     needs &= ~NEED_END;
3991        }
3992    
3993        if (needs) {
3994     printf(_("grubby: needs=%d, aborting\n"), needs);
3995     abort();
3996      }      }
3997    
3998      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 4001  int addNewKernel(struct grubConfig * con
4001      return 0;      return 0;
4002  }  }
4003    
4004    static void traceback(int signum)
4005    {
4006        void *array[40];
4007        size_t size;
4008    
4009        signal(SIGSEGV, SIG_DFL);
4010        memset(array, '\0', sizeof (array));
4011        size = backtrace(array, 40);
4012    
4013        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4014                (unsigned long)size);
4015        backtrace_symbols_fd(array, size, STDERR_FILENO);
4016        exit(1);
4017    }
4018    
4019  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4020      poptContext optCon;      poptContext optCon;
4021      char * grubConfig = NULL;      const char * grubConfig = NULL;
4022      char * outputFile = NULL;      char * outputFile = NULL;
4023      int arg = 0;      int arg = 0;
4024      int flags = 0;      int flags = 0;
4025      int badImageOkay = 0;      int badImageOkay = 0;
4026        int configureGrub2 = 0;
4027      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4028      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4029        int configureExtLinux = 0;
4030      int bootloaderProbe = 0;      int bootloaderProbe = 0;
4031        int extraInitrdCount = 0;
4032      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
4033      char * newKernelPath = NULL;      char * newKernelPath = NULL;
4034      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 4044  int main(int argc, const char ** argv) {
4044      char * defaultKernel = NULL;      char * defaultKernel = NULL;
4045      char * removeArgs = NULL;      char * removeArgs = NULL;
4046      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4047        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4048        char * envPath = NULL;
4049      const char * chptr = NULL;      const char * chptr = NULL;
4050      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4051      struct grubConfig * config;      struct grubConfig * config;
4052      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4053      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4054      int displayDefault = 0;      int displayDefault = 0;
4055        int displayDefaultIndex = 0;
4056        int displayDefaultTitle = 0;
4057        int defaultIndex = -1;
4058      struct poptOption options[] = {      struct poptOption options[] = {
4059   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4060      _("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 4072  int main(int argc, const char ** argv) {
4072   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4073      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4074      _("bootfs") },      _("bootfs") },
4075  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4076   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4077      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4078  #endif  #endif
4079   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4080      _("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 4085  int main(int argc, const char ** argv) {
4085        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4086        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4087        "template"), NULL },        "template"), NULL },
4088     { "debug", 0, 0, &debug, 0,
4089        _("print debugging information for failures") },
4090   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4091      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4092     { "default-index", 0, 0, &displayDefaultIndex, 0,
4093        _("display the index of the default kernel") },
4094     { "default-title", 0, 0, &displayDefaultTitle, 0,
4095        _("display the title of the default kernel") },
4096   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4097      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4098     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4099        _("force grub2 stanzas to use efi") },
4100     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4101        _("path for environment data"),
4102        _("path") },
4103     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4104        _("configure extlinux bootloader (from syslinux)") },
4105   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4106      _("configure grub bootloader") },      _("configure grub bootloader") },
4107     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4108        _("configure grub2 bootloader") },
4109   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4110      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4111      _("kernel-path") },      _("kernel-path") },
4112   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4113      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4114     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4115        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4116   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4117      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4118   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4132  int main(int argc, const char ** argv) {
4132   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4133      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4134        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4135     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4136        _("make the given entry index the default entry"),
4137        _("entry-index") },
4138   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4139      _("configure silo bootloader") },      _("configure silo bootloader") },
4140   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4152  int main(int argc, const char ** argv) {
4152   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4153      };      };
4154    
4155        useextlinuxmenu=0;
4156    
4157        signal(SIGSEGV, traceback);
4158    
4159        int i = 0;
4160        for (int j = 1; j < argc; j++)
4161     i += strlen(argv[j]) + 1;
4162        saved_command_line = malloc(i);
4163        if (!saved_command_line) {
4164     fprintf(stderr, "grubby: %m\n");
4165     exit(1);
4166        }
4167        saved_command_line[0] = '\0';
4168        for (int j = 1; j < argc; j++) {
4169     strcat(saved_command_line, argv[j]);
4170     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4171        }
4172    
4173      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4174      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4175    
# Line 2391  int main(int argc, const char ** argv) { Line 4179  int main(int argc, const char ** argv) {
4179      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4180      exit(0);      exit(0);
4181      break;      break;
4182      case 'i':
4183        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4184         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4185        } else {
4186     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4187     return 1;
4188        }
4189        break;
4190   }   }
4191      }      }
4192    
# Line 2406  int main(int argc, const char ** argv) { Line 4202  int main(int argc, const char ** argv) {
4202   return 1;   return 1;
4203      }      }
4204    
4205      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4206   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4207     configureExtLinux ) > 1) {
4208   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4209   return 1;   return 1;
4210      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4211   fprintf(stderr,   fprintf(stderr,
4212      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4213   return 1;   return 1;
4214        } else if (configureGrub2) {
4215     cfi = &grub2ConfigType;
4216     if (envPath)
4217        cfi->envFile = envPath;
4218      } else if (configureLilo) {      } else if (configureLilo) {
4219   cfi = &liloConfigType;   cfi = &liloConfigType;
4220      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4227  int main(int argc, const char ** argv) {
4227          cfi = &siloConfigType;          cfi = &siloConfigType;
4228      } else if (configureZipl) {      } else if (configureZipl) {
4229          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4230        } else if (configureExtLinux) {
4231     cfi = &extlinuxConfigType;
4232     useextlinuxmenu=1;
4233      }      }
4234    
4235      if (!cfi) {      if (!cfi) {
4236            if (grub2FindConfig(&grub2ConfigType))
4237        cfi = &grub2ConfigType;
4238     else
4239        #ifdef __ia64__        #ifdef __ia64__
4240   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4241        #elif __powerpc__        #elif __powerpc__
4242   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4243        #elif __sparc__        #elif __sparc__
4244          cfi = &siloConfigType;              cfi = &siloConfigType;
4245        #elif __s390__        #elif __s390__
4246          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4247        #elif __s390x__        #elif __s390x__
4248          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4249        #else        #else
4250   cfi = &grubConfigType;      cfi = &grubConfigType;
4251        #endif        #endif
4252      }      }
4253    
4254      if (!grubConfig)      if (!grubConfig) {
4255   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4256        grubConfig = cfi->findConfig(cfi);
4257     if (!grubConfig)
4258        grubConfig = cfi->defaultConfig;
4259        }
4260    
4261      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4262    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4263    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4264        (defaultIndex >= 0))) {
4265   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4266    "specified option"));    "specified option"));
4267   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4277  int main(int argc, const char ** argv) {
4277      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4278   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4279   return 1;   return 1;
4280      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4281    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4282    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4283   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4284   return 1;   return 1;
4285      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4303  int main(int argc, const char ** argv) {
4303   makeDefault = 1;   makeDefault = 1;
4304   defaultKernel = NULL;   defaultKernel = NULL;
4305      }      }
4306        else if (defaultKernel && (defaultIndex >= 0)) {
4307     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4308      "may not be used together\n"));
4309     return 1;
4310        }
4311    
4312      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4313   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4314   "is used\n"));   "is used\n"));
4315   return 1;   return 1;
4316      }      }
4317    
4318      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4319   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4320          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4321     && (defaultIndex == -1)) {
4322   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4323   return 1;   return 1;
4324      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4338  int main(int argc, const char ** argv) {
4338   bootPrefix = "";   bootPrefix = "";
4339      }      }
4340    
4341        if (!cfi->mbAllowExtraInitRds &&
4342     extraInitrdCount > 0) {
4343     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4344     return 1;
4345        }
4346    
4347      if (bootloaderProbe) {      if (bootloaderProbe) {
4348   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4349   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4350    
4351     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4352     if (grub2config) {
4353        gconfig = readConfig(grub2config, &grub2ConfigType);
4354        if (!gconfig)
4355     gr2c = 1;
4356        else
4357     gr2c = checkForGrub2(gconfig);
4358     }
4359    
4360   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4361      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4362        gconfig = readConfig(grubconfig, &grubConfigType);
4363      if (!gconfig)      if (!gconfig)
4364   grc = 1;   grc = 1;
4365      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4374  int main(int argc, const char ** argv) {
4374   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4375   }   }
4376    
4377   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4378        econfig = readConfig(eliloConfigType.defaultConfig,
4379     &eliloConfigType);
4380        if (!econfig)
4381     erc = 1;
4382        else
4383     erc = checkForElilo(econfig);
4384     }
4385    
4386     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4387        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4388        if (!lconfig)
4389     extrc = 1;
4390        else
4391     extrc = checkForExtLinux(lconfig);
4392     }
4393    
4394    
4395     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4396        yconfig = readConfig(yabootConfigType.defaultConfig,
4397     &yabootConfigType);
4398        if (!yconfig)
4399     yrc = 1;
4400        else
4401     yrc = checkForYaboot(yconfig);
4402     }
4403    
4404     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4405     erc == 1)
4406        return 1;
4407    
4408   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4409     if (gr2c == 2) printf("grub2\n");
4410   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4411     if (extrc == 2) printf("extlinux\n");
4412     if (yrc == 2) printf("yaboot\n");
4413     if (erc == 2) printf("elilo\n");
4414    
4415   return 0;   return 0;
4416      }      }
4417    
4418        if (grubConfig == NULL) {
4419     printf("Could not find bootloader configuration file.\n");
4420     exit(1);
4421        }
4422    
4423      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4424      if (!config) return 1;      if (!config) return 1;
4425    
# Line 2557  int main(int argc, const char ** argv) { Line 4429  int main(int argc, const char ** argv) {
4429          char * rootspec;          char * rootspec;
4430    
4431   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4432     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4433     cfi->defaultIsSaved)
4434        config->defaultImage = 0;
4435   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4436   if (!entry) return 0;   if (!entry) return 0;
4437   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4438    
4439   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4440   if (!line) return 0;   if (!line) return 0;
4441    
4442          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4444  int main(int argc, const char ** argv) {
4444                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4445    
4446   return 0;   return 0;
4447    
4448        } else if (displayDefaultTitle) {
4449     struct singleLine * line;
4450     struct singleEntry * entry;
4451    
4452     if (config->defaultImage == -1) return 0;
4453     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4454     cfi->defaultIsSaved)
4455        config->defaultImage = 0;
4456     entry = findEntryByIndex(config, config->defaultImage);
4457     if (!entry) return 0;
4458    
4459     if (!configureGrub2) {
4460      line = getLineByType(LT_TITLE, entry->lines);
4461      if (!line) return 0;
4462      printf("%s\n", line->elements[1].item);
4463    
4464     } else {
4465      char * title;
4466    
4467      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4468      line = getLineByType(LT_MENUENTRY, entry->lines);
4469      if (!line) return 0;
4470      title = grub2ExtractTitle(line);
4471      if (title)
4472        printf("%s\n", title);
4473     }
4474     return 0;
4475    
4476        } else if (displayDefaultIndex) {
4477            if (config->defaultImage == -1) return 0;
4478     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4479     cfi->defaultIsSaved)
4480        config->defaultImage = 0;
4481            printf("%i\n", config->defaultImage);
4482            return 0;
4483    
4484      } else if (kernelInfo)      } else if (kernelInfo)
4485   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4486    
# Line 2581  int main(int argc, const char ** argv) { Line 4492  int main(int argc, const char ** argv) {
4492      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4493      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4494      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4495      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4496      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4497      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4498                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4499        if (updateKernelPath && newKernelInitrd) {
4500                if (updateInitrd(config, updateKernelPath, bootPrefix,
4501                                 newKernelInitrd)) return 1;
4502        }
4503      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4504                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4505                         (const char **)extraInitrds, extraInitrdCount,
4506                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4507            
4508    
# Line 2597  int main(int argc, const char ** argv) { Line 4513  int main(int argc, const char ** argv) {
4513      }      }
4514    
4515      if (!outputFile)      if (!outputFile)
4516   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4517    
4518      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4519  }  }

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