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 2257 by niro, Mon Oct 21 14:01:48 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    
# Line 549  static struct grubConfig * readConfig(co Line 1077  static struct grubConfig * readConfig(co
1077      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1078      char * end;      char * end;
1079      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1080      int i, len;      int len;
1081      char * buf;      char * buf;
1082    
1083      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1084            printf("Could not find bootloader configuration\n");
1085            exit(1);
1086        } else if (!strcmp(inName, "-")) {
1087   in = 0;   in = 0;
1088      } else {      } else {
1089   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1126  static struct grubConfig * readConfig(co
1126      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1127   }   }
1128    
1129   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1130      sawEntry = 1;      sawEntry = 1;
1131      if (!entry) {      if (!entry) {
1132   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1142  static struct grubConfig * readConfig(co
1142      entry->next = NULL;      entry->next = NULL;
1143   }   }
1144    
1145   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1146        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1147        dbgPrintf("%s", line->indent);
1148        for (int i = 0; i < line->numElements; i++)
1149     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1150        dbgPrintf("\n");
1151        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1152        if (kwType && line->numElements == 3 &&
1153        !strcmp(line->elements[1].item, kwType->key) &&
1154        !is_special_grub2_variable(line->elements[2].item)) {
1155     dbgPrintf("Line sets default config\n");
1156     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1157     defaultLine = line;
1158        }
1159     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1160      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1161      defaultLine = line;      defaultLine = line;
1162    
1163            } else if (iskernel(line->type)) {
1164        /* if by some freak chance this is multiboot and the "module"
1165         * lines came earlier in the template, make sure to use LT_HYPER
1166         * instead of LT_KERNEL now
1167         */
1168        if (entry->multiboot)
1169     line->type = LT_HYPER;
1170    
1171          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1172        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1173         * instead, now that we know this is a multiboot entry.
1174         * This only applies to grub, but that's the only place we
1175         * should find LT_MBMODULE lines anyway.
1176         */
1177        for (struct singleLine *l = entry->lines; l; l = l->next) {
1178     if (l->type == LT_HYPER)
1179        break;
1180     else if (iskernel(l->type)) {
1181        l->type = LT_HYPER;
1182        break;
1183     }
1184        }
1185              entry->multiboot = 1;              entry->multiboot = 1;
1186    
1187     } else if (line->type == LT_HYPER) {
1188        entry->multiboot = 1;
1189    
1190   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1191      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1192      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1193    
1194   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1195      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1196      len = 0;      len = 0;
1197      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1198   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1199   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1200      }      }
1201      buf = malloc(len + 1);      buf = malloc(len + 1);
1202      *buf = '\0';      *buf = '\0';
1203    
1204      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1205   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1206   free(line->elements[i].item);   free(line->elements[i].item);
1207    
# Line 643  static struct grubConfig * readConfig(co Line 1215  static struct grubConfig * readConfig(co
1215      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1216      line->elements[1].item = buf;      line->elements[1].item = buf;
1217      line->numElements = 2;      line->numElements = 2;
1218     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1219        /* let --remove-kernel="TITLE=what" work */
1220        len = 0;
1221        char *extras;
1222        char *title;
1223    
1224        for (int i = 1; i < line->numElements; i++) {
1225     len += strlen(line->elements[i].item);
1226     len += strlen(line->elements[i].indent);
1227        }
1228        buf = malloc(len + 1);
1229        *buf = '\0';
1230    
1231        /* allocate mem for extra flags. */
1232        extras = malloc(len + 1);
1233        *extras = '\0';
1234    
1235        /* get title. */
1236        for (int i = 0; i < line->numElements; i++) {
1237     if (!strcmp(line->elements[i].item, "menuentry"))
1238        continue;
1239     if (isquote(*line->elements[i].item))
1240        title = line->elements[i].item + 1;
1241     else
1242        title = line->elements[i].item;
1243    
1244     len = strlen(title);
1245            if (isquote(title[len-1])) {
1246        strncat(buf, title,len-1);
1247        break;
1248     } else {
1249        strcat(buf, title);
1250        strcat(buf, line->elements[i].indent);
1251     }
1252        }
1253    
1254        /* get extras */
1255        int count = 0;
1256        for (int i = 0; i < line->numElements; i++) {
1257     if (count >= 2) {
1258        strcat(extras, line->elements[i].item);
1259        strcat(extras, line->elements[i].indent);
1260     }
1261    
1262     if (!strcmp(line->elements[i].item, "menuentry"))
1263        continue;
1264    
1265     /* count ' or ", there should be two in menuentry line. */
1266     if (isquote(*line->elements[i].item))
1267        count++;
1268    
1269     len = strlen(line->elements[i].item);
1270    
1271     if (isquote(line->elements[i].item[len -1]))
1272        count++;
1273    
1274     /* ok, we get the final ' or ", others are extras. */
1275                }
1276        line->elements[1].indent =
1277     line->elements[line->numElements - 2].indent;
1278        line->elements[1].item = buf;
1279        line->elements[2].indent =
1280     line->elements[line->numElements - 2].indent;
1281        line->elements[2].item = extras;
1282        line->numElements = 3;
1283   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1284      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1285         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 1288  static struct grubConfig * readConfig(co
1288      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1289   int last, len;   int last, len;
1290    
1291   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1292      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1293     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1294    
1295   last = line->numElements - 1;   last = line->numElements - 1;
1296   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1297   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1298      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1299      }      }
   
1300   }   }
1301    
1302   /* 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 1316  static struct grubConfig * readConfig(co
1316   movedLine = 1;   movedLine = 1;
1317   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1318   }   }
1319    
1320   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1321     which was moved, drop it. */     which was moved, drop it. */
1322   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 1332  static struct grubConfig * readConfig(co
1332   entry->lines = line;   entry->lines = line;
1333      else      else
1334   last->next = line;   last->next = line;
1335        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1336    
1337        /* we could have seen this outside of an entry... if so, we
1338         * ignore it like any other line we don't grok */
1339        if (line->type == LT_ENTRY_END && sawEntry)
1340     sawEntry = 0;
1341   } else {   } else {
1342      if (!cfg->theLines)      if (!cfg->theLines)
1343   cfg->theLines = line;   cfg->theLines = line;
1344      else {      else
1345   last->next = line;   last->next = line;
1346      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1347   }   }
1348    
1349   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1351  static struct grubConfig * readConfig(co
1351    
1352      free(incoming);      free(incoming);
1353    
1354        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1355      if (defaultLine) {      if (defaultLine) {
1356   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1357        cfi->defaultSupportSaved &&
1358        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1359     cfg->cfi->defaultIsSaved = 1;
1360     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1361     if (cfg->cfi->getEnv) {
1362        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1363        if (defTitle) {
1364     int index = 0;
1365     entry = findEntryByTitle(cfg, defTitle, &index);
1366     if (entry)
1367        cfg->defaultImage = index;
1368        }
1369     }
1370     } else if (cfi->defaultIsVariable) {
1371        char *value = defaultLine->elements[2].item;
1372        while (*value && (*value == '"' || *value == '\'' ||
1373        *value == ' ' || *value == '\t'))
1374     value++;
1375        cfg->defaultImage = strtol(value, &end, 10);
1376        while (*end && (*end == '"' || *end == '\'' ||
1377        *end == ' ' || *end == '\t'))
1378     end++;
1379        if (*end) cfg->defaultImage = -1;
1380     } else if (cfi->defaultSupportSaved &&
1381   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1382      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1383   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1384      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1385      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1386   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1387      i = 0;      int i = 0;
1388      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1389   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1390      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1398  static struct grubConfig * readConfig(co
1398                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1399                  }                  }
1400   i++;   i++;
1401     entry = NULL;
1402      }      }
1403    
1404      if (entry) cfg->defaultImage = i;      if (entry){
1405            cfg->defaultImage = i;
1406        }else{
1407            cfg->defaultImage = -1;
1408        }
1409     }
1410        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1411     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1412     if (defTitle) {
1413        int index = 0;
1414        entry = findEntryByTitle(cfg, defTitle, &index);
1415        if (entry)
1416     cfg->defaultImage = index;
1417   }   }
1418        } else {
1419            cfg->defaultImage = 0;
1420      }      }
1421    
1422      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1432  static void writeDefault(FILE * out, cha
1432    
1433      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1434   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1435      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1436     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1437     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1438        char *title;
1439        entry = findEntryByIndex(cfg, cfg->defaultImage);
1440        line = getLineByType(LT_MENUENTRY, entry->lines);
1441        if (!line)
1442     line = getLineByType(LT_TITLE, entry->lines);
1443        if (line) {
1444     title = extractTitle(line);
1445     if (title)
1446        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1447        }
1448     }
1449        } else if (cfg->defaultImage > -1) {
1450   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1451      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1452      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1453     cfg->defaultImage);
1454        } else {
1455     fprintf(out, "%sdefault%s%d\n", indent, separator,
1456     cfg->defaultImage);
1457        }
1458   } else {   } else {
1459      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1460    
# Line 769  static void writeDefault(FILE * out, cha Line 1471  static void writeDefault(FILE * out, cha
1471    
1472      if (!entry) return;      if (!entry) return;
1473    
1474      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1475    
1476      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1477   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1505  static int writeConfig(struct grubConfig
1505      int rc;      int rc;
1506    
1507      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1508         directory to / */         directory to the dir of the symlink */
1509      rc = chdir("/");      char *dir = strdupa(outName);
1510        rc = chdir(dirname(dir));
1511      do {      do {
1512   buf = alloca(len + 1);   buf = alloca(len + 1);
1513   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1514   if (rc == len) len += 256;   if (rc == len) len += 256;
1515      } while (rc == len);      } while (rc == len);
1516            
# Line 843  static int writeConfig(struct grubConfig Line 1545  static int writeConfig(struct grubConfig
1545      }      }
1546    
1547      line = cfg->theLines;      line = cfg->theLines;
1548        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1549      while (line) {      while (line) {
1550   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1551     line->numElements == 3 &&
1552     !strcmp(line->elements[1].item, defaultKw->key) &&
1553     !is_special_grub2_variable(line->elements[2].item)) {
1554        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1555        needs &= ~MAIN_DEFAULT;
1556     } else if (line->type == LT_DEFAULT) {
1557      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1558      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1559   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1621  static int numEntries(struct grubConfig
1621      return i;      return i;
1622  }  }
1623    
1624  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1625    int skipRemoved, int flags) {  {
1626      struct singleLine * line;      int fd;
1627      char * fullName;      char buf[65536];
1628      int i;      char *devname;
1629      struct stat sb, sb2;      char *chptr;
1630      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1631    
1632      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1633      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1634                        _PATH_MOUNTED, strerror(errno));
1635      if (!line) return 0;          return NULL;
1636      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1637    
1638      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1639        if (rc <= 0) {
1640            fprintf(stderr, "grubby: failed to read %s: %s\n",
1641                    _PATH_MOUNTED, strerror(errno));
1642            close(fd);
1643            return NULL;
1644        }
1645        close(fd);
1646        buf[rc] = '\0';
1647        chptr = buf;
1648    
1649      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;  
1650    
1651      for (i = 2; i < line->numElements; i++)      while (chptr && chptr != buf+rc) {
1652   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          devname = chptr;
     if (i < line->numElements) {  
  dev = line->elements[i].item + 5;  
     } else {  
  /* look for a lilo style LT_ROOT line */  
  line = entry->lines;  
  while (line && line->type != LT_ROOT) line = line->next;  
1653    
1654   if (line && line->numElements >= 2) {          /*
1655      dev = line->elements[1].item;           * The first column of a mtab entry is the device, but if the entry is a
1656   } else {           * special device it won't start with /, so move on to the next line.
1657              int type;           */
1658      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */          if (*devname != '/') {
1659      line = entry->lines;              chptr = strchr(chptr, '\n');
1660                if (chptr)
1661                    chptr++;
1662                continue;
1663            }
1664    
1665              type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);          /* Seek to the next space */
1666            chptr = strchr(chptr, ' ');
1667            if (!chptr) {
1668                fprintf(stderr, "grubby: error parsing %s: %s\n",
1669                        _PATH_MOUNTED, strerror(errno));
1670                return NULL;
1671            }
1672    
1673            /*
1674             * The second column of a mtab entry is the mount point, we are looking
1675             * for '/' obviously.
1676             */
1677            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1678                /* remember the last / entry in mtab */
1679               foundanswer = devname;
1680            }
1681    
1682            /* Next line */
1683            chptr = strchr(chptr, '\n');
1684            if (chptr)
1685                chptr++;
1686        }
1687    
1688        /* Return the last / entry found */
1689        if (foundanswer) {
1690            chptr = strchr(foundanswer, ' ');
1691            *chptr = '\0';
1692            return strdup(foundanswer);
1693        }
1694    
1695        return NULL;
1696    }
1697    
1698    void printEntry(struct singleEntry * entry, FILE *f) {
1699        int i;
1700        struct singleLine * line;
1701    
1702        for (line = entry->lines; line; line = line->next) {
1703     log_message(f, "DBG: %s", line->indent);
1704     for (i = 0; i < line->numElements; i++) {
1705        /* Need to handle this, because we strip the quotes from
1706         * menuentry when read it. */
1707        if (line->type == LT_MENUENTRY && i == 1) {
1708     if(!isquote(*line->elements[i].item))
1709        log_message(f, "\'%s\'", line->elements[i].item);
1710     else
1711        log_message(f, "%s", line->elements[i].item);
1712     log_message(f, "%s", line->elements[i].indent);
1713    
1714     continue;
1715        }
1716        
1717        log_message(f, "%s%s",
1718        line->elements[i].item, line->elements[i].indent);
1719     }
1720     log_message(f, "\n");
1721        }
1722    }
1723    
1724    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1725    {
1726        static int once;
1727        va_list argp, argq;
1728    
1729        va_start(argp, fmt);
1730    
1731        va_copy(argq, argp);
1732        if (!once) {
1733     log_time(NULL);
1734     log_message(NULL, "command line: %s\n", saved_command_line);
1735        }
1736        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1737        log_vmessage(NULL, fmt, argq);
1738    
1739        printEntry(entry, NULL);
1740        va_end(argq);
1741    
1742        if (!debug) {
1743     once = 1;
1744         va_end(argp);
1745     return;
1746        }
1747    
1748        if (okay) {
1749     va_end(argp);
1750     return;
1751        }
1752    
1753        if (!once)
1754     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1755        once = 1;
1756        fprintf(stderr, "DBG: Image entry failed: ");
1757        vfprintf(stderr, fmt, argp);
1758        printEntry(entry, stderr);
1759        va_end(argp);
1760    }
1761    
1762    #define beginswith(s, c) ((s) && (s)[0] == (c))
1763    
1764    static int endswith(const char *s, char c)
1765    {
1766     int slen;
1767    
1768     if (!s || !s[0])
1769     return 0;
1770     slen = strlen(s) - 1;
1771    
1772     return s[slen] == c;
1773    }
1774    
1775    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1776      int skipRemoved, int flags) {
1777        struct singleLine * line;
1778        char * fullName;
1779        int i;
1780        char * dev;
1781        char * rootspec;
1782        char * rootdev;
1783    
1784        if (skipRemoved && entry->skip) {
1785     notSuitablePrintf(entry, 0, "marked to skip\n");
1786     return 0;
1787        }
1788    
1789        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1790        if (!line) {
1791     notSuitablePrintf(entry, 0, "no line found\n");
1792     return 0;
1793        }
1794        if (line->numElements < 2) {
1795     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1796        line->numElements);
1797     return 0;
1798        }
1799    
1800        if (flags & GRUBBY_BADIMAGE_OKAY) {
1801        notSuitablePrintf(entry, 1, "\n");
1802        return 1;
1803        }
1804    
1805        fullName = alloca(strlen(bootPrefix) +
1806          strlen(line->elements[1].item) + 1);
1807        rootspec = getRootSpecifier(line->elements[1].item);
1808        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1809        int hasslash = endswith(bootPrefix, '/') ||
1810         beginswith(line->elements[1].item + rootspec_offset, '/');
1811        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1812                line->elements[1].item + rootspec_offset);
1813        if (access(fullName, R_OK)) {
1814     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1815     return 0;
1816        }
1817        for (i = 2; i < line->numElements; i++)
1818     if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1819        if (i < line->numElements) {
1820     dev = line->elements[i].item + 5;
1821        } else {
1822     /* look for a lilo style LT_ROOT line */
1823     line = getLineByType(LT_ROOT, entry->lines);
1824    
1825      while (line && line->type != type) line = line->next;   if (line && line->numElements >= 2) {
1826        dev = line->elements[1].item;
1827     } else {
1828        /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1829         * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1830         */
1831        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1832    
1833              /* failed to find one */              /* failed to find one */
1834              if (!line) return 0;              if (!line) {
1835     notSuitablePrintf(entry, 0, "no line found\n");
1836     return 0;
1837                }
1838    
1839      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1840          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1841      if (i < line->numElements)      if (i < line->numElements)
1842          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1843      else {      else {
1844     notSuitablePrintf(entry, 0, "no root= entry found\n");
1845   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1846          return 0;          return 0;
1847              }              }
1848   }   }
1849      }      }
1850    
1851      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1852   dev += 6;      if (!getpathbyspec(dev)) {
1853            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1854   /* check which device has this label */          return 0;
1855   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1856   if (!dev) return 0;   dev = getpathbyspec(dev);
1857    
1858        rootdev = findDiskForRoot();
1859        if (!rootdev) {
1860            notSuitablePrintf(entry, 0, "can't find root device\n");
1861     return 0;
1862      }      }
1863    
1864      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1865   if (stat(dev, &sb))          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1866      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1867      } else {          free(rootdev);
1868   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1869   if (*end) return 0;      }
1870    
1871        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1872            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1873     getuuidbydev(rootdev), getuuidbydev(dev));
1874     free(rootdev);
1875            return 0;
1876      }      }
     stat("/", &sb2);  
1877    
1878      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1879        notSuitablePrintf(entry, 1, "\n");
1880    
1881      return 1;      return 1;
1882  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1920  struct singleEntry * findEntryByPath(str
1920   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1921   if (!entry) return NULL;   if (!entry) return NULL;
1922    
1923   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1924   if (!line) return NULL;   if (!line) return NULL;
1925    
1926   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1958  struct singleEntry * findEntryByPath(str
1958    
1959   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1960      prefix = "";      prefix = "";
1961      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1962      kernel += 6;      kernel += 6;
1963   }   }
1964    
1965   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1966      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1967    
1968        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1969    
1970      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1971                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1972          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
1973                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1974                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1975                      break;   else if (checkType & LT_KERNEL)
1976              }      ct = checkType | LT_KERNEL_EFI;
1977                 line = getLineByType(ct, line);
1978              /* have to check multiboot lines too */   if (!line)
1979              if (entry->multiboot) {      break;  /* not found in this entry */
1980                  while (line && line->type != LT_MBMODULE) line = line->next;  
1981                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
1982                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
1983                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
1984                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
1985                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
1986                          break;   kernel + strlen(prefix)))
1987                  }   break;
1988              }   }
1989     if(line->type == LT_MENUENTRY &&
1990     !strcmp(line->elements[1].item, kernel))
1991        break;
1992        }
1993    
1994      i++;      /* make sure this entry has a kernel identifier; this skips
1995         * non-Linux boot entries (could find netbsd etc, though, which is
1996         * unfortunate)
1997         */
1998        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1999     break; /* found 'im! */
2000   }   }
2001    
2002   if (index) *index = i;   if (index) *index = i;
2003      }      }
2004    
2005      if (!entry) return NULL;      return entry;
2006    }
2007    
2008      /* make sure this entry has a kernel identifier; this skips non-Linux  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2009         boot entries (could find netbsd etc, though, which is unfortunate) */        int * index) {
2010      line = entry->lines;      struct singleEntry * entry;
2011      while (line && line->type != LT_KERNEL) line = line->next;      struct singleLine * line;
2012      if (!line) {      int i;
2013   if (!index) index = &i;      char * newtitle;
2014   (*index)++;  
2015   return findEntryByPath(config, kernel, prefix, index);      for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2016     if (index && i < *index)
2017        continue;
2018     line = getLineByType(LT_TITLE, entry->lines);
2019     if (!line)
2020        line = getLineByType(LT_MENUENTRY, entry->lines);
2021     if (!line)
2022        continue;
2023     newtitle = grub2ExtractTitle(line);
2024     if (!newtitle)
2025        continue;
2026     if (!strcmp(title, newtitle))
2027        break;
2028      }      }
2029    
2030        if (!entry)
2031     return NULL;
2032    
2033        if (index)
2034     *index = i;
2035      return entry;      return entry;
2036  }  }
2037    
# Line 1147  struct singleEntry * findTemplate(struct Line 2057  struct singleEntry * findTemplate(struct
2057      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2058      int index;      int index;
2059    
2060      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2061     if (cfg->cfi->getEnv) {
2062        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2063        if (defTitle) {
2064     int index = 0;
2065     entry = findEntryByTitle(cfg, defTitle, &index);
2066        }
2067     }
2068        } else if (cfg->defaultImage > -1) {
2069   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2070   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2071      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1200  void markRemovedImage(struct grubConfig Line 2118  void markRemovedImage(struct grubConfig
2118        const char * prefix) {        const char * prefix) {
2119      struct singleEntry * entry;      struct singleEntry * entry;
2120    
2121      if (!image) return;      if (!image)
2122     return;
2123    
2124        /* check and see if we're removing the default image */
2125        if (isdigit(*image)) {
2126     entry = findEntryByPath(cfg, image, prefix, NULL);
2127     if(entry)
2128        entry->skip = 1;
2129     return;
2130        }
2131    
2132      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2133   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 2135  void markRemovedImage(struct grubConfig
2135    
2136  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2137       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2138       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2139      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2140      int i, j;      int i, j;
2141    
2142      if (newIsDefault) {      if (newIsDefault) {
2143   config->defaultImage = 0;   config->defaultImage = 0;
2144   return;   return;
2145        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2146     if (findEntryByIndex(config, index))
2147        config->defaultImage = index;
2148     else
2149        config->defaultImage = -1;
2150     return;
2151      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2152   i = 0;   i = 0;
2153   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 2160  void setDefaultImage(struct grubConfig *
2160    
2161      /* 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
2162         changes */         changes */
2163      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2164     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2165        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2166        return;        return;
2167    
# Line 1286  void displayEntry(struct singleEntry * e Line 2220  void displayEntry(struct singleEntry * e
2220      char * root = NULL;      char * root = NULL;
2221      int i;      int i;
2222    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2223      printf("index=%d\n", index);      printf("index=%d\n", index);
2224    
2225      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
2226        if (!line) {
2227            printf("non linux entry\n");
2228            return;
2229        }
2230    
2231        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2232     printf("kernel=%s\n", line->elements[1].item);
2233        else
2234     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2235    
2236      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2237   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2248  void displayEntry(struct singleEntry * e
2248   }   }
2249   printf("\"\n");   printf("\"\n");
2250      } else {      } else {
2251   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2252   if (line) {   if (line) {
2253      char * s;      char * s;
2254    
# Line 1334  void displayEntry(struct singleEntry * e Line 2272  void displayEntry(struct singleEntry * e
2272      }      }
2273    
2274      if (!root) {      if (!root) {
2275   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2276   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2277      root=line->elements[1].item;      root=line->elements[1].item;
2278      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2287  void displayEntry(struct singleEntry * e
2287   printf("root=%s\n", s);   printf("root=%s\n", s);
2288      }      }
2289    
2290      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2291    
2292      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2293   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2294        printf("initrd=");
2295     else
2296        printf("initrd=%s", prefix);
2297    
2298   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2299      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2300   printf("\n");   printf("\n");
2301      }      }
2302    
2303        line = getLineByType(LT_TITLE, entry->lines);
2304        if (line) {
2305     printf("title=%s\n", line->elements[1].item);
2306        } else {
2307     char * title;
2308     line = getLineByType(LT_MENUENTRY, entry->lines);
2309     title = grub2ExtractTitle(line);
2310     if (title)
2311        printf("title=%s\n", title);
2312        }
2313    }
2314    
2315    int isSuseSystem(void) {
2316        const char * path;
2317        const static char default_path[] = "/etc/SuSE-release";
2318    
2319        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2320     path = default_path;
2321    
2322        if (!access(path, R_OK))
2323     return 1;
2324        return 0;
2325    }
2326    
2327    int isSuseGrubConf(const char * path) {
2328        FILE * grubConf;
2329        char * line = NULL;
2330        size_t len = 0, res = 0;
2331    
2332        grubConf = fopen(path, "r");
2333        if (!grubConf) {
2334            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2335     return 0;
2336        }
2337    
2338        while ((res = getline(&line, &len, grubConf)) != -1) {
2339     if (!strncmp(line, "setup", 5)) {
2340        fclose(grubConf);
2341        free(line);
2342        return 1;
2343     }
2344        }
2345    
2346        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2347          path);
2348    
2349        fclose(grubConf);
2350        free(line);
2351        return 0;
2352    }
2353    
2354    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2355        FILE * grubConf;
2356        char * line = NULL;
2357        size_t res = 0, len = 0;
2358    
2359        if (!path) return 1;
2360        if (!lbaPtr) return 1;
2361    
2362        grubConf = fopen(path, "r");
2363        if (!grubConf) return 1;
2364    
2365        while ((res = getline(&line, &len, grubConf)) != -1) {
2366     if (line[res - 1] == '\n')
2367        line[res - 1] = '\0';
2368     else if (len > res)
2369        line[res] = '\0';
2370     else {
2371        line = realloc(line, res + 1);
2372        line[res] = '\0';
2373     }
2374    
2375     if (!strncmp(line, "setup", 5)) {
2376        if (strstr(line, "--force-lba")) {
2377            *lbaPtr = 1;
2378        } else {
2379            *lbaPtr = 0;
2380        }
2381        dbgPrintf("lba: %i\n", *lbaPtr);
2382        break;
2383     }
2384        }
2385    
2386        free(line);
2387        fclose(grubConf);
2388        return 0;
2389    }
2390    
2391    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2392        FILE * grubConf;
2393        char * line = NULL;
2394        size_t res = 0, len = 0;
2395        char * lastParamPtr = NULL;
2396        char * secLastParamPtr = NULL;
2397        char installDeviceNumber = '\0';
2398        char * bounds = NULL;
2399    
2400        if (!path) return 1;
2401        if (!devicePtr) return 1;
2402    
2403        grubConf = fopen(path, "r");
2404        if (!grubConf) return 1;
2405    
2406        while ((res = getline(&line, &len, grubConf)) != -1) {
2407     if (strncmp(line, "setup", 5))
2408        continue;
2409    
2410     if (line[res - 1] == '\n')
2411        line[res - 1] = '\0';
2412     else if (len > res)
2413        line[res] = '\0';
2414     else {
2415        line = realloc(line, res + 1);
2416        line[res] = '\0';
2417     }
2418    
2419     lastParamPtr = bounds = line + res;
2420    
2421     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2422     while (!isspace(*lastParamPtr))
2423        lastParamPtr--;
2424     lastParamPtr++;
2425    
2426     secLastParamPtr = lastParamPtr - 2;
2427     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2428    
2429     if (lastParamPtr + 3 > bounds) {
2430        dbgPrintf("lastParamPtr going over boundary");
2431        fclose(grubConf);
2432        free(line);
2433        return 1;
2434     }
2435     if (!strncmp(lastParamPtr, "(hd", 3))
2436        lastParamPtr += 3;
2437     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2438    
2439     /*
2440     * Second last parameter will decide wether last parameter is
2441     * an IMAGE_DEVICE or INSTALL_DEVICE
2442     */
2443     while (!isspace(*secLastParamPtr))
2444        secLastParamPtr--;
2445     secLastParamPtr++;
2446    
2447     if (secLastParamPtr + 3 > bounds) {
2448        dbgPrintf("secLastParamPtr going over boundary");
2449        fclose(grubConf);
2450        free(line);
2451        return 1;
2452     }
2453     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2454     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2455        secLastParamPtr += 3;
2456        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2457        installDeviceNumber = *secLastParamPtr;
2458     } else {
2459        installDeviceNumber = *lastParamPtr;
2460     }
2461    
2462     *devicePtr = malloc(6);
2463     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2464     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2465     fclose(grubConf);
2466     free(line);
2467     return 0;
2468        }
2469    
2470        free(line);
2471        fclose(grubConf);
2472        return 1;
2473    }
2474    
2475    int grubGetBootFromDeviceMap(const char * device,
2476         char ** bootPtr) {
2477        FILE * deviceMap;
2478        char * line = NULL;
2479        size_t res = 0, len = 0;
2480        char * devicePtr;
2481        char * bounds = NULL;
2482        const char * path;
2483        const static char default_path[] = "/boot/grub/device.map";
2484    
2485        if (!device) return 1;
2486        if (!bootPtr) return 1;
2487    
2488        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2489     path = default_path;
2490    
2491        dbgPrintf("opening grub device.map file from: %s\n", path);
2492        deviceMap = fopen(path, "r");
2493        if (!deviceMap)
2494     return 1;
2495    
2496        while ((res = getline(&line, &len, deviceMap)) != -1) {
2497            if (!strncmp(line, "#", 1))
2498        continue;
2499    
2500     if (line[res - 1] == '\n')
2501        line[res - 1] = '\0';
2502     else if (len > res)
2503        line[res] = '\0';
2504     else {
2505        line = realloc(line, res + 1);
2506        line[res] = '\0';
2507     }
2508    
2509     devicePtr = line;
2510     bounds = line + res;
2511    
2512     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2513        devicePtr++;
2514     dbgPrintf("device: %s\n", devicePtr);
2515    
2516     if (!strncmp(devicePtr, device, strlen(device))) {
2517        devicePtr += strlen(device);
2518        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2519            devicePtr++;
2520    
2521        *bootPtr = strdup(devicePtr);
2522        break;
2523     }
2524        }
2525    
2526        free(line);
2527        fclose(deviceMap);
2528        return 0;
2529    }
2530    
2531    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2532        char * grubDevice;
2533    
2534        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2535     dbgPrintf("error looking for grub installation device\n");
2536        else
2537     dbgPrintf("grubby installation device: %s\n", grubDevice);
2538    
2539        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2540     dbgPrintf("error looking for grub boot device\n");
2541        else
2542     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2543    
2544        free(grubDevice);
2545        return 0;
2546    }
2547    
2548    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2549        /*
2550         * This SuSE grub configuration file at this location is not your average
2551         * grub configuration file, but instead the grub commands used to setup
2552         * grub on that system.
2553         */
2554        const char * path;
2555        const static char default_path[] = "/etc/grub.conf";
2556    
2557        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2558     path = default_path;
2559    
2560        if (!isSuseGrubConf(path)) return 1;
2561    
2562        if (lbaPtr) {
2563            *lbaPtr = 0;
2564            if (suseGrubConfGetLba(path, lbaPtr))
2565                return 1;
2566        }
2567    
2568        if (bootPtr) {
2569            *bootPtr = NULL;
2570            suseGrubConfGetBoot(path, bootPtr);
2571        }
2572    
2573        return 0;
2574  }  }
2575    
2576  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2580  int parseSysconfigGrub(int * lbaPtr, cha
2580      char * start;      char * start;
2581      char * param;      char * param;
2582    
2583      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2584      if (!in) return 1;      if (!in) return 1;
2585    
2586      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2621  int parseSysconfigGrub(int * lbaPtr, cha
2621  }  }
2622    
2623  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2624      char * boot;      char * boot = NULL;
2625      int lba;      int lba;
2626    
2627      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2628   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2629   if (boot) printf("boot=%s\n", boot);      free(boot);
2630        return;
2631     }
2632        } else {
2633            if (parseSysconfigGrub(&lba, &boot)) {
2634        free(boot);
2635        return;
2636     }
2637        }
2638    
2639        if (lba) printf("lba\n");
2640        if (boot) {
2641     printf("boot=%s\n", boot);
2642     free(boot);
2643      }      }
2644  }  }
2645    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2655  int displayInfo(struct grubConfig * conf
2655   return 1;   return 1;
2656      }      }
2657    
2658      /* 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
2659         be a better way */         be a better way */
2660      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2661   dumpSysconfigGrub();   dumpSysconfigGrub();
2662      } else {      } else {
2663   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2664   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2665      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2666   }   }
2667    
2668   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2669   if (line) printf("lba\n");   if (line) printf("lba\n");
2670      }      }
2671    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2680  int displayInfo(struct grubConfig * conf
2680      return 0;      return 0;
2681  }  }
2682    
2683    struct singleLine * addLineTmpl(struct singleEntry * entry,
2684     struct singleLine * tmplLine,
2685     struct singleLine * prevLine,
2686     const char * val,
2687     struct configFileInfo * cfi)
2688    {
2689        struct singleLine * newLine = lineDup(tmplLine);
2690    
2691        if (isEfi && cfi == &grub2ConfigType) {
2692     enum lineType_e old = newLine->type;
2693     newLine->type = preferredLineType(newLine->type, cfi);
2694     if (old != newLine->type)
2695        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2696        }
2697    
2698        if (val) {
2699     /* override the inherited value with our own.
2700     * This is a little weak because it only applies to elements[1]
2701     */
2702     if (newLine->numElements > 1)
2703        removeElement(newLine, 1);
2704     insertElement(newLine, val, 1, cfi);
2705    
2706     /* but try to keep the rootspec from the template... sigh */
2707     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2708        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2709        if (rootspec != NULL) {
2710     free(newLine->elements[1].item);
2711     newLine->elements[1].item =
2712        sdupprintf("%s%s", rootspec, val);
2713        }
2714     }
2715        }
2716    
2717        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2718          newLine->elements[0].item : "");
2719    
2720        if (!entry->lines) {
2721     /* first one on the list */
2722     entry->lines = newLine;
2723        } else if (prevLine) {
2724     /* add after prevLine */
2725     newLine->next = prevLine->next;
2726     prevLine->next = newLine;
2727        }
2728    
2729        return newLine;
2730    }
2731    
2732  /* val may be NULL */  /* val may be NULL */
2733  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2734       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2735       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2736       char * val) {       const char * val) {
2737      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2738      int i;      struct keywordTypes * kw;
2739        struct singleLine tmpl;
2740    
2741      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2742   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2743      if (type != LT_TITLE || !cfi->titleBracketed)       */
2744          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2745     /* we're doing a bracketed title (zipl) */
2746     tmpl.type = type;
2747     tmpl.numElements = 1;
2748     tmpl.elements = alloca(sizeof(*tmpl.elements));
2749     tmpl.elements[0].item = alloca(strlen(val)+3);
2750     sprintf(tmpl.elements[0].item, "[%s]", val);
2751     tmpl.elements[0].indent = "";
2752     val = NULL;
2753        } else if (type == LT_MENUENTRY) {
2754     char *lineend = "--class gnu-linux --class gnu --class os {";
2755     if (!val) {
2756        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2757        abort();
2758     }
2759     kw = getKeywordByType(type, cfi);
2760     if (!kw) {
2761        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2762        abort();
2763     }
2764     tmpl.indent = "";
2765     tmpl.type = type;
2766     tmpl.numElements = 3;
2767     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2768     tmpl.elements[0].item = kw->key;
2769     tmpl.elements[0].indent = alloca(2);
2770     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2771     tmpl.elements[1].item = (char *)val;
2772     tmpl.elements[1].indent = alloca(2);
2773     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2774     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2775     strcpy(tmpl.elements[2].item, lineend);
2776     tmpl.elements[2].indent = "";
2777        } else {
2778     kw = getKeywordByType(type, cfi);
2779     if (!kw) {
2780        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2781        abort();
2782     }
2783     tmpl.type = type;
2784     tmpl.numElements = val ? 2 : 1;
2785     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2786     tmpl.elements[0].item = kw->key;
2787     tmpl.elements[0].indent = alloca(2);
2788     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2789     if (val) {
2790        tmpl.elements[1].item = (char *)val;
2791        tmpl.elements[1].indent = "";
2792     }
2793        }
2794    
2795      /* 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
2796         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2797         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
2798         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2799         differently from the rest) */         differently from the rest) */
2800      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2801   line = entry->lines;   if (line->numElements) prev = line;
2802   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2803   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;  
2804      }      }
2805    
2806      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2807          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2808          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2809          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2810          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2811          line->elements[0].indent = malloc(2);   else
2812          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2813          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2814             if (menuEntry)
2815          if (val) {      tmpl.indent = "\t";
2816              line->elements[1].item = val;   else if (prev == entry->lines)
2817              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2818          }   else
2819      } 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("");  
2820      }      }
2821    
2822      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2823  }  }
2824    
2825  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2844  void removeLine(struct singleEntry * ent
2844      free(line);      free(line);
2845  }  }
2846    
2847    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2848    {
2849        struct singleLine newLine = {
2850     .indent = tmplLine->indent,
2851     .type = tmplLine->type,
2852     .next = tmplLine->next,
2853        };
2854        int firstQuotedItem = -1;
2855        int quoteLen = 0;
2856        int j;
2857        int element = 0;
2858        char *c;
2859    
2860        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2861        strcpy(c, tmplLine->elements[0].item);
2862        insertElement(&newLine, c, element++, cfi);
2863        free(c);
2864        c = NULL;
2865    
2866        for (j = 1; j < tmplLine->numElements; j++) {
2867     if (firstQuotedItem == -1) {
2868        quoteLen += strlen(tmplLine->elements[j].item);
2869        
2870        if (isquote(tmplLine->elements[j].item[0])) {
2871     firstQuotedItem = j;
2872            quoteLen += strlen(tmplLine->elements[j].indent);
2873        } else {
2874     c = malloc(quoteLen + 1);
2875     strcpy(c, tmplLine->elements[j].item);
2876     insertElement(&newLine, c, element++, cfi);
2877     free(c);
2878     quoteLen = 0;
2879        }
2880     } else {
2881        int itemlen = strlen(tmplLine->elements[j].item);
2882        quoteLen += itemlen;
2883        quoteLen += strlen(tmplLine->elements[j].indent);
2884        
2885        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2886     c = malloc(quoteLen + 1);
2887     c[0] = '\0';
2888     for (int i = firstQuotedItem; i < j+1; i++) {
2889        strcat(c, tmplLine->elements[i].item);
2890        strcat(c, tmplLine->elements[i].indent);
2891     }
2892     insertElement(&newLine, c, element++, cfi);
2893     free(c);
2894    
2895     firstQuotedItem = -1;
2896     quoteLen = 0;
2897        }
2898     }
2899        }
2900        while (tmplLine->numElements)
2901     removeElement(tmplLine, 0);
2902        if (tmplLine->elements)
2903     free(tmplLine->elements);
2904    
2905        tmplLine->numElements = newLine.numElements;
2906        tmplLine->elements = newLine.elements;
2907    }
2908    
2909    static void insertElement(struct singleLine * line,
2910      const char * item, int insertHere,
2911      struct configFileInfo * cfi)
2912    {
2913        struct keywordTypes * kw;
2914        char indent[2] = "";
2915    
2916        /* sanity check */
2917        if (insertHere > line->numElements) {
2918     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2919      insertHere, line->numElements);
2920     insertHere = line->numElements;
2921        }
2922    
2923        line->elements = realloc(line->elements, (line->numElements + 1) *
2924         sizeof(*line->elements));
2925        memmove(&line->elements[insertHere+1],
2926        &line->elements[insertHere],
2927        (line->numElements - insertHere) *
2928        sizeof(*line->elements));
2929        line->elements[insertHere].item = strdup(item);
2930    
2931        kw = getKeywordByType(line->type, cfi);
2932    
2933        if (line->numElements == 0) {
2934     indent[0] = '\0';
2935        } else if (insertHere == 0) {
2936     indent[0] = kw->nextChar;
2937        } else if (kw->separatorChar != '\0') {
2938     indent[0] = kw->separatorChar;
2939        } else {
2940     indent[0] = ' ';
2941        }
2942    
2943        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2944     /* move the end-of-line forward */
2945     line->elements[insertHere].indent =
2946        line->elements[insertHere-1].indent;
2947     line->elements[insertHere-1].indent = strdup(indent);
2948        } else {
2949     line->elements[insertHere].indent = strdup(indent);
2950        }
2951    
2952        line->numElements++;
2953    
2954        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2955          line->elements[0].item,
2956          line->elements[insertHere].item,
2957          line->elements[insertHere].indent,
2958          insertHere);
2959    }
2960    
2961    static void removeElement(struct singleLine * line, int removeHere) {
2962        int i;
2963    
2964        /* sanity check */
2965        if (removeHere >= line->numElements) return;
2966    
2967        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2968          removeHere, line->elements[removeHere].item);
2969    
2970        free(line->elements[removeHere].item);
2971    
2972        if (removeHere > 1) {
2973     /* previous argument gets this argument's post-indentation */
2974     free(line->elements[removeHere-1].indent);
2975     line->elements[removeHere-1].indent =
2976        line->elements[removeHere].indent;
2977        } else {
2978     free(line->elements[removeHere].indent);
2979        }
2980    
2981        /* now collapse the array, but don't bother to realloc smaller */
2982        for (i = removeHere; i < line->numElements - 1; i++)
2983     line->elements[i] = line->elements[i + 1];
2984    
2985        line->numElements--;
2986    }
2987    
2988  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2989      char * first, * second;      char * first, * second;
2990      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 3007  int updateActualImage(struct grubConfig
3007      struct singleEntry * entry;      struct singleEntry * entry;
3008      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
3009      int index = 0;      int index = 0;
3010      int i, j, k;      int i, k;
3011      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
3012      const char ** arg;      const char ** arg;
3013      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
3014      int firstElement;      int firstElement;
3015      int *usedElements, *usedArgs;      int *usedElements;
3016        int doreplace;
3017    
3018      if (!image) return 0;      if (!image) return 0;
3019    
# Line 1609  int updateActualImage(struct grubConfig Line 3040  int updateActualImage(struct grubConfig
3040   }   }
3041      }      }
3042    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
3043    
3044      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
3045   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
3046    
3047      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3048   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
3049    
3050      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
3051    
3052      k = 0;   if (multibootArgs && !entry->multiboot)
3053      for (arg = newArgs; *arg; arg++)      continue;
3054          k++;  
3055      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
3056     * LT_KERNELARGS, use that.  Otherwise use
3057     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
3058     */
3059     if (useKernelArgs) {
3060        line = getLineByType(LT_KERNELARGS, entry->lines);
3061        if (!line) {
3062     /* no LT_KERNELARGS, need to add it */
3063     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
3064           cfg->secondaryIndent, NULL);
3065        }
3066        firstElement = 1;
3067    
3068      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
3069   index++;      line = getLineByType(LT_HYPER, entry->lines);
3070        if (!line) {
3071     /* a multiboot entry without LT_HYPER? */
3072     continue;
3073        }
3074        firstElement = 2;
3075    
3076   line = entry->lines;   } else {
3077   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
3078   if (!line) continue;      if (!line) {
3079   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3080     continue;
3081          if (entry->multiboot && !multibootArgs) {      }
3082              /* 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;  
3083   }   }
3084    
3085   if (!line && useKernelArgs) {   /* handle the elilo case which does:
3086      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
3087      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
3088     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
3089        /* this is a multiboot entry, make sure there's
3090         * -- on the args line
3091         */
3092        for (i = firstElement; i < line->numElements; i++) {
3093     if (!strcmp(line->elements[i].item, "--"))
3094        break;
3095        }
3096        if (i == line->numElements) {
3097     /* assume all existing args are kernel args,
3098     * prepend -- to make it official
3099     */
3100     insertElement(line, "--", firstElement, cfg->cfi);
3101     i = firstElement;
3102        }
3103        if (!multibootArgs) {
3104     /* kernel args start after the -- */
3105     firstElement = i + 1;
3106        }
3107     } else if (cfg->cfi->mbConcatArgs) {
3108        /* this is a non-multiboot entry, remove hyper args */
3109        for (i = firstElement; i < line->numElements; i++) {
3110     if (!strcmp(line->elements[i].item, "--"))
3111        break;
3112        }
3113        if (i < line->numElements) {
3114     /* remove args up to -- */
3115     while (strcmp(line->elements[firstElement].item, "--"))
3116        removeElement(line, firstElement);
3117     /* remove -- */
3118     removeElement(line, firstElement);
3119        }
3120   }   }
3121    
3122          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
3123    
3124          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
3125   for (arg = newArgs; *arg; arg++) {  
3126              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
3127      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
3128     if (multibootArgs && cfg->cfi->mbConcatArgs &&
3129        !strcmp(line->elements[i].item, "--"))
3130     {
3131        /* reached the end of hyper args, insert here */
3132        doreplace = 0;
3133        break;  
3134     }
3135                  if (usedElements[i])                  if (usedElements[i])
3136                      continue;                      continue;
3137   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3138                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3139      break;      break;
3140                  }                  }
3141              }              }
     chptr = strchr(*arg, '=');  
3142    
3143      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
3144   /* replace */   /* direct replacement */
3145   free(line->elements[i].item);   free(line->elements[i].item);
3146   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("");  
  }  
3147    
3148   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
3149   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
3150      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
3151   /* append */   if (rootLine) {
3152   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
3153   (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(" ");  
3154   } else {   } else {
3155      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
3156         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
3157   }   }
3158        }
3159    
3160   line->numElements++;      else {
3161     /* insert/append */
3162     insertElement(line, *arg, i, cfg->cfi);
3163     usedElements = realloc(usedElements, line->numElements *
3164           sizeof(*usedElements));
3165     memmove(&usedElements[i + 1], &usedElements[i],
3166     line->numElements - i - 1);
3167     usedElements[i] = 1;
3168    
3169   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
3170     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
3171     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
3172   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
3173      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
3174      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
3175   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
3176   }   }
3177      }      }
             k++;  
3178   }   }
3179    
3180          free(usedElements);          free(usedElements);
3181    
  /* 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? */  
3182   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
3183      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3184   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3185        !strcmp(line->elements[i].item, "--"))
3186        /* reached the end of hyper args, stop here */
3187        break;
3188     if (!argMatch(line->elements[i].item, *arg)) {
3189        removeElement(line, i);
3190      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;  
3191   }   }
3192        }
3193   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3194        if (useRoot && !strncmp(*arg, "root=", 5)) {
3195   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3196      line->elements[j - 1] = line->elements[j];   if (rootLine)
3197        removeLine(entry, rootLine);
  line->numElements--;  
3198      }      }
3199   }   }
3200    
# Line 1760  int updateActualImage(struct grubConfig Line 3205  int updateActualImage(struct grubConfig
3205   }   }
3206      }      }
3207    
     free(usedArgs);  
3208      free(newArgs);      free(newArgs);
3209      free(oldArgs);      free(oldArgs);
3210    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3230  int updateImage(struct grubConfig * cfg,
3230      return rc;      return rc;
3231  }  }
3232    
3233    int updateInitrd(struct grubConfig * cfg, const char * image,
3234                     const char * prefix, const char * initrd) {
3235        struct singleEntry * entry;
3236        struct singleLine * line, * kernelLine, *endLine = NULL;
3237        int index = 0;
3238    
3239        if (!image) return 0;
3240    
3241        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3242            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3243            if (!kernelLine) continue;
3244    
3245            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3246            if (line)
3247                removeLine(entry, line);
3248            if (prefix) {
3249                int prefixLen = strlen(prefix);
3250                if (!strncmp(initrd, prefix, prefixLen))
3251                    initrd += prefixLen;
3252            }
3253     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3254     if (endLine)
3255        removeLine(entry, endLine);
3256            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3257     kernelLine->indent, initrd);
3258            if (!line)
3259        return 1;
3260     if (endLine) {
3261        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3262                if (!line)
3263     return 1;
3264     }
3265    
3266            break;
3267        }
3268    
3269        return 0;
3270    }
3271    
3272  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3273      int fd;      int fd;
3274      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3292  int checkDeviceBootloader(const char * d
3292      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3293   return 0;   return 0;
3294    
3295      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3296   offset = boot[2] + 2;   offset = boot[2] + 2;
3297      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3298   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3299      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3300   offset = boot[1] + 2;        offset = boot[1] + 2;
3301            /*
3302     * it looks like grub, when copying stage1 into the mbr, patches stage1
3303     * right after the JMP location, replacing other instructions such as
3304     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3305     * different bytes.
3306     */
3307          if ((bootSect[offset + 1] == NOOP_OPCODE)
3308      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3309     offset = offset + 3;
3310          }
3311      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3312   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3313      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3449  int checkForLilo(struct grubConfig * con
3449      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3450  }  }
3451    
3452    int checkForGrub2(struct grubConfig * config) {
3453        if (!access("/etc/grub.d/", R_OK))
3454     return 2;
3455    
3456        return 1;
3457    }
3458    
3459  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3460      int fd;      int fd;
3461      unsigned char bootSect[512];      unsigned char bootSect[512];
3462      char * boot;      char * boot;
3463        int onSuse = isSuseSystem();
3464    
3465      if (parseSysconfigGrub(NULL, &boot))  
3466   return 0;      if (onSuse) {
3467     if (parseSuseGrubConf(NULL, &boot))
3468        return 0;
3469        } else {
3470     if (parseSysconfigGrub(NULL, &boot))
3471        return 0;
3472        }
3473    
3474      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3475      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3483  int checkForGrub(struct grubConfig * con
3483      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3484   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3485   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3486     close(fd);
3487     return 1;
3488        }
3489        close(fd);
3490    
3491        /* The more elaborate checks do not work on SuSE. The checks done
3492         * seem to be reasonble (at least for now), so just return success
3493         */
3494        if (onSuse)
3495     return 2;
3496    
3497        return checkDeviceBootloader(boot, bootSect);
3498    }
3499    
3500    int checkForExtLinux(struct grubConfig * config) {
3501        int fd;
3502        unsigned char bootSect[512];
3503        char * boot;
3504        char executable[] = "/boot/extlinux/extlinux";
3505    
3506        printf("entered: checkForExtLinux()\n");
3507    
3508        if (parseSysconfigGrub(NULL, &boot))
3509     return 0;
3510    
3511        /* assume grub is not installed -- not an error condition */
3512        if (!boot)
3513     return 0;
3514    
3515        fd = open(executable, O_RDONLY);
3516        if (fd < 0)
3517     /* this doesn't exist if grub hasn't been installed */
3518     return 0;
3519    
3520        if (read(fd, bootSect, 512) != 512) {
3521     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3522     executable, strerror(errno));
3523   return 1;   return 1;
3524      }      }
3525      close(fd);      close(fd);
# Line 1983  int checkForGrub(struct grubConfig * con Line 3527  int checkForGrub(struct grubConfig * con
3527      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3528  }  }
3529    
3530    int checkForYaboot(struct grubConfig * config) {
3531        /*
3532         * This is a simplistic check that we consider good enough for own puporses
3533         *
3534         * If we were to properly check if yaboot is *installed* we'd need to:
3535         * 1) get the system boot device (LT_BOOT)
3536         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3537         *    the content on the boot device
3538         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3539         * 4) check again if binary and boot device contents match
3540         */
3541        if (!access("/etc/yaboot.conf", R_OK))
3542     return 2;
3543    
3544        return 1;
3545    }
3546    
3547    int checkForElilo(struct grubConfig * config) {
3548        if (!access("/etc/elilo.conf", R_OK))
3549     return 2;
3550    
3551        return 1;
3552    }
3553    
3554  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3555      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3556    
# Line 1994  static char * getRootSpecifier(char * st Line 3562  static char * getRootSpecifier(char * st
3562      return rootspec;      return rootspec;
3563  }  }
3564    
3565    static char * getInitrdVal(struct grubConfig * config,
3566       const char * prefix, struct singleLine *tmplLine,
3567       const char * newKernelInitrd,
3568       const char ** extraInitrds, int extraInitrdCount)
3569    {
3570        char *initrdVal, *end;
3571        int i;
3572        size_t totalSize;
3573        size_t prefixLen;
3574        char separatorChar;
3575    
3576        prefixLen = strlen(prefix);
3577        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3578    
3579        for (i = 0; i < extraInitrdCount; i++) {
3580     totalSize += sizeof(separatorChar);
3581     totalSize += strlen(extraInitrds[i]) - prefixLen;
3582        }
3583    
3584        initrdVal = end = malloc(totalSize);
3585    
3586        end = stpcpy (end, newKernelInitrd + prefixLen);
3587    
3588        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3589        for (i = 0; i < extraInitrdCount; i++) {
3590     const char *extraInitrd;
3591     int j;
3592    
3593     extraInitrd = extraInitrds[i] + prefixLen;
3594     /* Don't add entries that are already there */
3595     if (tmplLine != NULL) {
3596        for (j = 2; j < tmplLine->numElements; j++)
3597     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3598        break;
3599    
3600        if (j != tmplLine->numElements)
3601     continue;
3602     }
3603    
3604     *end++ = separatorChar;
3605     end = stpcpy(end, extraInitrd);
3606        }
3607    
3608        return initrdVal;
3609    }
3610    
3611  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3612           const char * prefix,           const char * prefix,
3613   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3614   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3615                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3616                     const char * newMBKernel, const char * newMBKernelArgs) {
3617      struct singleEntry * new;      struct singleEntry * new;
3618      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3619      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3620      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3621    
3622      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3623    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3647  int addNewKernel(struct grubConfig * con
3647      config->entries = new;      config->entries = new;
3648    
3649      /* copy/update from the template */      /* copy/update from the template */
3650      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3651        if (newKernelInitrd)
3652     needs |= NEED_INITRD;
3653      if (newMBKernel) {      if (newMBKernel) {
3654          needs |= KERNEL_MB;          needs |= NEED_MB;
3655          new->multiboot = 1;          new->multiboot = 1;
3656      }      }
3657    
3658      if (template) {      if (template) {
3659   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3660      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3661      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3662   indent = tmplLine->indent;   {
3663        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3664    
3665      /* skip comments */      /* skip comments */
3666      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3667      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3668      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3669    
3670      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3671      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3672        /* it's not a multiboot template and this is the kernel
3673              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3674                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3675                  struct singleLine *l;       */
3676                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3677     /* insert the hypervisor first */
3678                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3679                                    config->secondaryIndent,    tmplLine->indent,
3680                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3681                     /* set up for adding the kernel line */
3682                  tmplLine = lastLine;   free(tmplLine->indent);
3683                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3684                      new->lines = l;   needs &= ~NEED_MB;
3685                  } else {      }
3686                      newLine->next = l;      if (needs & NEED_KERNEL) {
3687                      newLine = l;   /* use addLineTmpl to preserve line elements,
3688                  }   * otherwise we could just call addLine.  Unfortunately
3689                  continue;   * this means making some changes to the template
3690              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3691                         template->multiboot && !new->multiboot) {   * change below.
3692                  continue; /* don't need multiboot kernel here */   */
3693              }   struct keywordTypes * mbm_kw =
3694        getKeywordByType(LT_MBMODULE, config->cfi);
3695      if (!new->lines) {   if (mbm_kw) {
3696   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3697   new->lines = newLine;      free(tmplLine->elements[0].item);
3698      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3699   newLine->next = malloc(sizeof(*newLine));   }
3700   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3701      }        newKernelPath + strlen(prefix), config->cfi);
3702     needs &= ~NEED_KERNEL;
3703        }
3704        if (needs & NEED_MB) { /* !mbHyperFirst */
3705     newLine = addLine(new, config->cfi, LT_HYPER,
3706      config->secondaryIndent,
3707      newMBKernel + strlen(prefix));
3708     needs &= ~NEED_MB;
3709        }
3710     } else if (needs & NEED_KERNEL) {
3711        newLine = addLineTmpl(new, tmplLine, newLine,
3712      newKernelPath + strlen(prefix), config->cfi);
3713        needs &= ~NEED_KERNEL;
3714     }
3715    
3716        } else if (tmplLine->type == LT_HYPER &&
3717           tmplLine->numElements >= 2) {
3718     if (needs & NEED_MB) {
3719        newLine = addLineTmpl(new, tmplLine, newLine,
3720      newMBKernel + strlen(prefix), config->cfi);
3721        needs &= ~NEED_MB;
3722     }
3723    
3724      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3725      newLine->next = NULL;         tmplLine->numElements >= 2) {
3726      newLine->type = tmplLine->type;   if (new->multiboot) {
3727      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3728      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3729      newLine->numElements);        newKernelPath +
3730      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3731   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3732   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3733   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3734      }   char *initrdVal;
3735     initrdVal = getInitrdVal(config, prefix, tmplLine,
3736              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3737      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3738                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3739                  if (!template->multiboot) {        initrdVal, config->cfi);
3740                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3741                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3742                  } else {      }
3743                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3744                      repl = newMBKernel;      /* template is multi but new is not,
3745                  }       * insert the kernel in the first module slot
3746                  if (new->multiboot && !template->multiboot) {       */
3747                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3748                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3749                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3750                  }   strdup(getKeywordByType(tmplLine->type,
3751   free(newLine->elements[1].item);   config->cfi)->key);
3752                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3753                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3754                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3755                                                             rootspec,      needs &= ~NEED_KERNEL;
3756                                                             repl +   } else if (needs & NEED_INITRD) {
3757                                                             strlen(prefix));      char *initrdVal;
3758                  } else {      /* template is multi but new is not,
3759                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3760                                                         strlen(prefix));       */
3761                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3762              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3763                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3764                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3765                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3766                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3767                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3768                      newLine->type = LT_KERNEL;      free(initrdVal);
3769                  }      needs &= ~NEED_INITRD;
3770   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;  
3771    
3772   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3773      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3774      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3775        config->cfi->mbInitRdIsModule) {
3776        /* make sure we don't insert the module initrd
3777         * before the module kernel... if we don't do it here,
3778         * it will be inserted following the template.
3779         */
3780        if (!needs & NEED_KERNEL) {
3781     char *initrdVal;
3782    
3783     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3784     newLine = addLine(new, config->cfi, LT_MBMODULE,
3785      config->secondaryIndent,
3786      initrdVal);
3787     free(initrdVal);
3788     needs &= ~NEED_INITRD;
3789        }
3790     } else if (needs & NEED_INITRD) {
3791        char *initrdVal;
3792        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3793        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3794        free(initrdVal);
3795        needs &= ~NEED_INITRD;
3796   }   }
3797    
3798   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3799   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3800   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3801     char *nkt = malloc(strlen(newKernelTitle)+3);
3802     strcpy(nkt, "'");
3803     strcat(nkt, newKernelTitle);
3804     strcat(nkt, "'");
3805     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3806     free(nkt);
3807     needs &= ~NEED_TITLE;
3808      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3809                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3810                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3811                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3812                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3813                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3814                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3815                                             newLine->numElements);     config->cfi->titleBracketed) {
3816        /* addLineTmpl doesn't handle titleBracketed */
3817                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3818                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3819                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3820                  newLine->numElements = 1;   }
3821              }      } else if (tmplLine->type == LT_ECHO) {
3822        requote(tmplLine, config->cfi);
3823        static const char *prefix = "'Loading ";
3824        if (tmplLine->numElements > 1 &&
3825        strstr(tmplLine->elements[1].item, prefix) &&
3826        masterLine->next &&
3827        iskernel(masterLine->next->type)) {
3828     char *newTitle = malloc(strlen(prefix) +
3829     strlen(newKernelTitle) + 2);
3830    
3831     strcpy(newTitle, prefix);
3832     strcat(newTitle, newKernelTitle);
3833     strcat(newTitle, "'");
3834     newLine = addLine(new, config->cfi, LT_ECHO,
3835     tmplLine->indent, newTitle);
3836     free(newTitle);
3837        } else {
3838     /* pass through other lines from the template */
3839     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3840     config->cfi);
3841        }
3842        } else {
3843     /* pass through other lines from the template */
3844     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3845        }
3846   }   }
3847    
3848      } else {      } else {
3849   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3850      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3851     */
3852     switch (config->cfi->entryStart) {
3853        case LT_KERNEL:
3854        case LT_KERNEL_EFI:
3855     if (new->multiboot && config->cfi->mbHyperFirst) {
3856        /* fall through to LT_HYPER */
3857     } else {
3858        newLine = addLine(new, config->cfi,
3859              preferredLineType(LT_KERNEL, config->cfi),
3860          config->primaryIndent,
3861          newKernelPath + strlen(prefix));
3862        needs &= ~NEED_KERNEL;
3863        break;
3864     }
3865    
3866        case LT_HYPER:
3867     newLine = addLine(new, config->cfi, LT_HYPER,
3868      config->primaryIndent,
3869      newMBKernel + strlen(prefix));
3870     needs &= ~NEED_MB;
3871   break;   break;
         }  
3872    
3873   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3874      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3875       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3876       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3877      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3878       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3879      default:        config->primaryIndent, nkt);
3880                  /* zipl strikes again */   free(nkt);
3881                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3882                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3883                      chptr = newKernelTitle;   break;
3884                      type = LT_TITLE;      }
3885                      break;      case LT_TITLE:
3886                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3887                      abort();   char * templabel;
3888                  }   int x = 0, y = 0;
3889   }  
3890     templabel = strdup(newKernelTitle);
3891     while( templabel[x]){
3892     if( templabel[x] == ' ' ){
3893     y = x;
3894     while( templabel[y] ){
3895     templabel[y] = templabel[y+1];
3896     y++;
3897     }
3898     }
3899     x++;
3900     }
3901     newLine = addLine(new, config->cfi, LT_TITLE,
3902      config->primaryIndent, templabel);
3903     free(templabel);
3904     }else{
3905     newLine = addLine(new, config->cfi, LT_TITLE,
3906      config->primaryIndent, newKernelTitle);
3907     }
3908     needs &= ~NEED_TITLE;
3909     break;
3910    
3911   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3912   new->lines = newLine;   abort();
3913     }
3914      }      }
3915    
3916      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3917          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3918              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3919                                config->secondaryIndent,       */
3920                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3921          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3922              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3923                                config->secondaryIndent,    newKernelTitle);
3924                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3925          /* don't need to check for title as it's guaranteed to have been      }
3926           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3927           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3928          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3929              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3930                                config->secondaryIndent,   needs &= ~NEED_MB;
3931                                newKernelInitrd + strlen(prefix));      }
3932      } else {      if (needs & NEED_KERNEL) {
3933          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3934              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3935                                config->secondaryIndent,        config->cfi))
3936                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3937          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3938              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3939                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3940                                newKernelTitle);   needs &= ~NEED_KERNEL;
3941          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3942              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3943                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3944                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3945      newMBKernel + strlen(prefix));
3946     needs &= ~NEED_MB;
3947        }
3948        if (needs & NEED_INITRD) {
3949     char *initrdVal;
3950     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3951     newLine = addLine(new, config->cfi,
3952      (new->multiboot && getKeywordByType(LT_MBMODULE,
3953          config->cfi))
3954       ? LT_MBMODULE
3955       : preferredLineType(LT_INITRD, config->cfi),
3956      config->secondaryIndent,
3957      initrdVal);
3958     free(initrdVal);
3959     needs &= ~NEED_INITRD;
3960        }
3961        if (needs & NEED_END) {
3962     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3963     config->secondaryIndent, NULL);
3964     needs &= ~NEED_END;
3965        }
3966    
3967        if (needs) {
3968     printf(_("grubby: needs=%d, aborting\n"), needs);
3969     abort();
3970      }      }
3971    
3972      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3975  int addNewKernel(struct grubConfig * con
3975      return 0;      return 0;
3976  }  }
3977    
3978    static void traceback(int signum)
3979    {
3980        void *array[40];
3981        size_t size;
3982    
3983        signal(SIGSEGV, SIG_DFL);
3984        memset(array, '\0', sizeof (array));
3985        size = backtrace(array, 40);
3986    
3987        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
3988                (unsigned long)size);
3989        backtrace_symbols_fd(array, size, STDERR_FILENO);
3990        exit(1);
3991    }
3992    
3993  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3994      poptContext optCon;      poptContext optCon;
3995      char * grubConfig = NULL;      const char * grubConfig = NULL;
3996      char * outputFile = NULL;      char * outputFile = NULL;
3997      int arg = 0;      int arg = 0;
3998      int flags = 0;      int flags = 0;
3999      int badImageOkay = 0;      int badImageOkay = 0;
4000        int configureGrub2 = 0;
4001      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4002      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4003        int configureExtLinux = 0;
4004      int bootloaderProbe = 0;      int bootloaderProbe = 0;
4005        int extraInitrdCount = 0;
4006      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
4007      char * newKernelPath = NULL;      char * newKernelPath = NULL;
4008      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 4018  int main(int argc, const char ** argv) {
4018      char * defaultKernel = NULL;      char * defaultKernel = NULL;
4019      char * removeArgs = NULL;      char * removeArgs = NULL;
4020      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4021        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4022        char * envPath = NULL;
4023      const char * chptr = NULL;      const char * chptr = NULL;
4024      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4025      struct grubConfig * config;      struct grubConfig * config;
4026      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4027      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4028      int displayDefault = 0;      int displayDefault = 0;
4029        int displayDefaultIndex = 0;
4030        int displayDefaultTitle = 0;
4031        int defaultIndex = -1;
4032      struct poptOption options[] = {      struct poptOption options[] = {
4033   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4034      _("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 4046  int main(int argc, const char ** argv) {
4046   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4047      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4048      _("bootfs") },      _("bootfs") },
4049  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4050   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4051      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4052  #endif  #endif
4053   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4054      _("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 4059  int main(int argc, const char ** argv) {
4059        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4060        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4061        "template"), NULL },        "template"), NULL },
4062     { "debug", 0, 0, &debug, 0,
4063        _("print debugging information for failures") },
4064   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4065      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4066     { "default-index", 0, 0, &displayDefaultIndex, 0,
4067        _("display the index of the default kernel") },
4068     { "default-title", 0, 0, &displayDefaultTitle, 0,
4069        _("display the title of the default kernel") },
4070   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4071      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4072     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4073        _("force grub2 stanzas to use efi") },
4074     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4075        _("path for environment data"),
4076        _("path") },
4077     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4078        _("configure extlinux bootloader (from syslinux)") },
4079   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4080      _("configure grub bootloader") },      _("configure grub bootloader") },
4081     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4082        _("configure grub2 bootloader") },
4083   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4084      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4085      _("kernel-path") },      _("kernel-path") },
4086   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4087      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4088     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4089        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4090   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4091      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4092   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4106  int main(int argc, const char ** argv) {
4106   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4107      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4108        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4109     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4110        _("make the given entry index the default entry"),
4111        _("entry-index") },
4112   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4113      _("configure silo bootloader") },      _("configure silo bootloader") },
4114   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4126  int main(int argc, const char ** argv) {
4126   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4127      };      };
4128    
4129        useextlinuxmenu=0;
4130    
4131        signal(SIGSEGV, traceback);
4132    
4133        int i = 0;
4134        for (int j = 1; j < argc; j++)
4135     i += strlen(argv[j]) + 1;
4136        saved_command_line = malloc(i);
4137        if (!saved_command_line) {
4138     fprintf(stderr, "grubby: %m\n");
4139     exit(1);
4140        }
4141        saved_command_line[0] = '\0';
4142        for (int j = 1; j < argc; j++) {
4143     strcat(saved_command_line, argv[j]);
4144     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4145        }
4146    
4147      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4148      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4149    
# Line 2391  int main(int argc, const char ** argv) { Line 4153  int main(int argc, const char ** argv) {
4153      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4154      exit(0);      exit(0);
4155      break;      break;
4156      case 'i':
4157        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4158         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4159        } else {
4160     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4161     return 1;
4162        }
4163        break;
4164   }   }
4165      }      }
4166    
# Line 2406  int main(int argc, const char ** argv) { Line 4176  int main(int argc, const char ** argv) {
4176   return 1;   return 1;
4177      }      }
4178    
4179      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4180   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4181     configureExtLinux ) > 1) {
4182   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4183   return 1;   return 1;
4184      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4185   fprintf(stderr,   fprintf(stderr,
4186      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4187   return 1;   return 1;
4188        } else if (configureGrub2) {
4189     cfi = &grub2ConfigType;
4190     if (envPath)
4191        cfi->envFile = envPath;
4192      } else if (configureLilo) {      } else if (configureLilo) {
4193   cfi = &liloConfigType;   cfi = &liloConfigType;
4194      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4201  int main(int argc, const char ** argv) {
4201          cfi = &siloConfigType;          cfi = &siloConfigType;
4202      } else if (configureZipl) {      } else if (configureZipl) {
4203          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4204        } else if (configureExtLinux) {
4205     cfi = &extlinuxConfigType;
4206     useextlinuxmenu=1;
4207      }      }
4208    
4209      if (!cfi) {      if (!cfi) {
4210            if (grub2FindConfig(&grub2ConfigType))
4211        cfi = &grub2ConfigType;
4212     else
4213        #ifdef __ia64__        #ifdef __ia64__
4214   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4215        #elif __powerpc__        #elif __powerpc__
4216   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4217        #elif __sparc__        #elif __sparc__
4218          cfi = &siloConfigType;              cfi = &siloConfigType;
4219        #elif __s390__        #elif __s390__
4220          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4221        #elif __s390x__        #elif __s390x__
4222          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4223        #else        #else
4224   cfi = &grubConfigType;      cfi = &grubConfigType;
4225        #endif        #endif
4226      }      }
4227    
4228      if (!grubConfig)      if (!grubConfig) {
4229   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4230        grubConfig = cfi->findConfig(cfi);
4231     if (!grubConfig)
4232        grubConfig = cfi->defaultConfig;
4233        }
4234    
4235      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4236    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4237    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4238        (defaultIndex >= 0))) {
4239   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4240    "specified option"));    "specified option"));
4241   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4251  int main(int argc, const char ** argv) {
4251      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4252   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4253   return 1;   return 1;
4254      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4255    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4256    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4257   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4258   return 1;   return 1;
4259      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4277  int main(int argc, const char ** argv) {
4277   makeDefault = 1;   makeDefault = 1;
4278   defaultKernel = NULL;   defaultKernel = NULL;
4279      }      }
4280        else if (defaultKernel && (defaultIndex >= 0)) {
4281     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4282      "may not be used together\n"));
4283     return 1;
4284        }
4285    
4286      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4287   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4288   "is used\n"));   "is used\n"));
4289   return 1;   return 1;
4290      }      }
4291    
4292      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4293   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4294          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4295     && (defaultIndex == -1)) {
4296   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4297   return 1;   return 1;
4298      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4312  int main(int argc, const char ** argv) {
4312   bootPrefix = "";   bootPrefix = "";
4313      }      }
4314    
4315        if (!cfi->mbAllowExtraInitRds &&
4316     extraInitrdCount > 0) {
4317     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4318     return 1;
4319        }
4320    
4321      if (bootloaderProbe) {      if (bootloaderProbe) {
4322   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4323   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4324    
4325     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4326     if (grub2config) {
4327        gconfig = readConfig(grub2config, &grub2ConfigType);
4328        if (!gconfig)
4329     gr2c = 1;
4330        else
4331     gr2c = checkForGrub2(gconfig);
4332     }
4333    
4334   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4335      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4336        gconfig = readConfig(grubconfig, &grubConfigType);
4337      if (!gconfig)      if (!gconfig)
4338   grc = 1;   grc = 1;
4339      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4348  int main(int argc, const char ** argv) {
4348   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4349   }   }
4350    
4351   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4352        econfig = readConfig(eliloConfigType.defaultConfig,
4353     &eliloConfigType);
4354        if (!econfig)
4355     erc = 1;
4356        else
4357     erc = checkForElilo(econfig);
4358     }
4359    
4360     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4361        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4362        if (!lconfig)
4363     extrc = 1;
4364        else
4365     extrc = checkForExtLinux(lconfig);
4366     }
4367    
4368    
4369     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4370        yconfig = readConfig(yabootConfigType.defaultConfig,
4371     &yabootConfigType);
4372        if (!yconfig)
4373     yrc = 1;
4374        else
4375     yrc = checkForYaboot(yconfig);
4376     }
4377    
4378     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4379     erc == 1)
4380        return 1;
4381    
4382   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4383     if (gr2c == 2) printf("grub2\n");
4384   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4385     if (extrc == 2) printf("extlinux\n");
4386     if (yrc == 2) printf("yaboot\n");
4387     if (erc == 2) printf("elilo\n");
4388    
4389   return 0;   return 0;
4390      }      }
4391    
4392        if (grubConfig == NULL) {
4393     printf("Could not find bootloader configuration file.\n");
4394     exit(1);
4395        }
4396    
4397      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4398      if (!config) return 1;      if (!config) return 1;
4399    
# Line 2557  int main(int argc, const char ** argv) { Line 4403  int main(int argc, const char ** argv) {
4403          char * rootspec;          char * rootspec;
4404    
4405   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4406     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4407     cfi->defaultIsSaved)
4408        config->defaultImage = 0;
4409   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4410   if (!entry) return 0;   if (!entry) return 0;
4411   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4412    
4413   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4414   if (!line) return 0;   if (!line) return 0;
4415    
4416          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4418  int main(int argc, const char ** argv) {
4418                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4419    
4420   return 0;   return 0;
4421    
4422        } else if (displayDefaultTitle) {
4423     struct singleLine * line;
4424     struct singleEntry * entry;
4425    
4426     if (config->defaultImage == -1) return 0;
4427     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4428     cfi->defaultIsSaved)
4429        config->defaultImage = 0;
4430     entry = findEntryByIndex(config, config->defaultImage);
4431     if (!entry) return 0;
4432    
4433     if (!configureGrub2) {
4434      line = getLineByType(LT_TITLE, entry->lines);
4435      if (!line) return 0;
4436      printf("%s\n", line->elements[1].item);
4437    
4438     } else {
4439      char * title;
4440    
4441      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4442      line = getLineByType(LT_MENUENTRY, entry->lines);
4443      if (!line) return 0;
4444      title = grub2ExtractTitle(line);
4445      if (title)
4446        printf("%s\n", title);
4447     }
4448     return 0;
4449    
4450        } else if (displayDefaultIndex) {
4451            if (config->defaultImage == -1) return 0;
4452     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4453     cfi->defaultIsSaved)
4454        config->defaultImage = 0;
4455            printf("%i\n", config->defaultImage);
4456            return 0;
4457    
4458      } else if (kernelInfo)      } else if (kernelInfo)
4459   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4460    
# Line 2581  int main(int argc, const char ** argv) { Line 4466  int main(int argc, const char ** argv) {
4466      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4467      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4468      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4469      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4470      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4471      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4472                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4473        if (updateKernelPath && newKernelInitrd) {
4474                if (updateInitrd(config, updateKernelPath, bootPrefix,
4475                                 newKernelInitrd)) return 1;
4476        }
4477      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4478                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4479                         (const char **)extraInitrds, extraInitrdCount,
4480                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4481            
4482    
# Line 2597  int main(int argc, const char ** argv) { Line 4487  int main(int argc, const char ** argv) {
4487      }      }
4488    
4489      if (!outputFile)      if (!outputFile)
4490   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4491    
4492      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4493  }  }

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