Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 2683 by niro, Wed Jul 16 09:51:14 2014 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_KERNEL_16    = 1 << 22,
94        LT_INITRD_16    = 1 << 23,
95        LT_UNKNOWN      = 1 << 24,
96    };
97    
98  struct singleLine {  struct singleLine {
99      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 114  struct singleEntry {
114    
115  #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 */
116    
117  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
118  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
119  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
120  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
121  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
122    #define NEED_MB      (1 << 4)
123    #define NEED_END     (1 << 5)
124    
125  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
126  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
127    #define DEFAULT_SAVED_GRUB2 -3
128    
129  struct keywordTypes {  struct keywordTypes {
130      char * key;      char * key;
131      enum lineType_e type;      enum lineType_e type;
132      char nextChar;      char nextChar;
133  } ;      char separatorChar;
134    };
135    
136    struct configFileInfo;
137    
138    typedef const char *(*findConfigFunc)(struct configFileInfo *);
139    typedef const int (*writeLineFunc)(struct configFileInfo *,
140     struct singleLine *line);
141    typedef char *(*getEnvFunc)(struct configFileInfo *, char *name);
142    typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value);
143    
144  struct configFileInfo {  struct configFileInfo {
145      char * defaultConfig;      char * defaultConfig;
146        findConfigFunc findConfig;
147        writeLineFunc writeLine;
148        getEnvFunc getEnv;
149        setEnvFunc setEnv;
150      struct keywordTypes * keywords;      struct keywordTypes * keywords;
151        int caseInsensitive;
152      int defaultIsIndex;      int defaultIsIndex;
153        int defaultIsVariable;
154      int defaultSupportSaved;      int defaultSupportSaved;
155      enum lineType_e entrySeparator;      int defaultIsSaved;
156        enum lineType_e entryStart;
157        enum lineType_e entryEnd;
158      int needsBootPrefix;      int needsBootPrefix;
159      int argsInQuotes;      int argsInQuotes;
160      int maxTitleLength;      int maxTitleLength;
161      int titleBracketed;      int titleBracketed;
162        int titlePosition;
163        int mbHyperFirst;
164        int mbInitRdIsModule;
165        int mbConcatArgs;
166        int mbAllowExtraInitRds;
167        char *envFile;
168  };  };
169    
170  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 173  struct keywordTypes grubKeywords[] = {
173      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
174      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
175      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
176      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
177      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
178        { "kernel",     LT_HYPER,       ' ' },
179      { NULL,    0, 0 },      { NULL,    0, 0 },
180  };  };
181    
182    const char *grubFindConfig(struct configFileInfo *cfi) {
183        static const char *configFiles[] = {
184     "/boot/grub/grub.conf",
185     "/boot/grub/menu.lst",
186     "/etc/grub.conf",
187     "/boot/grub2/grub.cfg",
188     "/boot/grub2-efi/grub.cfg",
189     NULL
190        };
191        static int i = -1;
192    
193        if (i == -1) {
194     for (i = 0; configFiles[i] != NULL; i++) {
195        dbgPrintf("Checking \"%s\": ", configFiles[i]);
196        if (!access(configFiles[i], R_OK)) {
197     dbgPrintf("found\n");
198     return configFiles[i];
199        }
200        dbgPrintf("not found\n");
201     }
202        }
203        return configFiles[i];
204    }
205    
206  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
207      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
208      grubKeywords,    /* keywords */      .keywords = grubKeywords,
209      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
210      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
211      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
212      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
213      0,    /* argsInQuotes */      .mbHyperFirst = 1,
214      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
215      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
216    };
217    
218    struct keywordTypes grub2Keywords[] = {
219        { "menuentry",  LT_MENUENTRY,   ' ' },
220        { "}",          LT_ENTRY_END,   ' ' },
221        { "echo",       LT_ECHO,        ' ' },
222        { "set",        LT_SET_VARIABLE,' ', '=' },
223        { "root",       LT_BOOTROOT,    ' ' },
224        { "default",    LT_DEFAULT,     ' ' },
225        { "fallback",   LT_FALLBACK,    ' ' },
226        { "linux",      LT_KERNEL,      ' ' },
227        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
228        { "linux16",    LT_KERNEL_16,   ' ' },
229        { "initrd",     LT_INITRD,      ' ', ' ' },
230        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
231        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
232        { "module",     LT_MBMODULE,    ' ' },
233        { "kernel",     LT_HYPER,       ' ' },
234        { NULL, 0, 0 },
235    };
236    
237    const char *grub2FindConfig(struct configFileInfo *cfi) {
238        static const char *configFiles[] = {
239     "/boot/grub/grub-efi.cfg",
240     "/boot/grub/grub.cfg",
241     NULL
242        };
243        static int i = -1;
244        static const char *grub_cfg = "/boot/grub/grub.cfg";
245        int rc = -1;
246    
247        if (i == -1) {
248     for (i = 0; configFiles[i] != NULL; i++) {
249        dbgPrintf("Checking \"%s\": ", configFiles[i]);
250        if ((rc = access(configFiles[i], R_OK))) {
251     if (errno == EACCES) {
252        printf("Unable to access bootloader configuration file "
253           "\"%s\": %m\n", configFiles[i]);
254        exit(1);
255     }
256     continue;
257        } else {
258     dbgPrintf("found\n");
259     return configFiles[i];
260        }
261     }
262        }
263    
264        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
265         * that isn't in grub1, and if it exists, return the config file path
266         * that they use. */
267        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
268     dbgPrintf("found\n");
269     return grub_cfg;
270        }
271    
272        dbgPrintf("not found\n");
273        return configFiles[i];
274    }
275    
276    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
277    static char *grub2GetEnv(struct configFileInfo *info, char *name)
278    {
279        static char buf[1025];
280        char *s = NULL;
281        char *ret = NULL;
282        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
283        int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name);
284    
285        if (rc < 0)
286     return NULL;
287    
288        FILE *f = popen(s, "r");
289        if (!f)
290     goto out;
291    
292        memset(buf, '\0', sizeof (buf));
293        ret = fgets(buf, 1024, f);
294        pclose(f);
295    
296        if (ret) {
297     ret += strlen(name) + 1;
298     ret[strlen(ret) - 1] = '\0';
299        }
300        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
301    out:
302        free(s);
303        return ret;
304    }
305    
306    static int sPopCount(const char *s, const char *c)
307    {
308        int ret = 0;
309        if (!s)
310     return -1;
311        for (int i = 0; s[i] != '\0'; i++)
312     for (int j = 0; c[j] != '\0'; j++)
313        if (s[i] == c[j])
314     ret++;
315        return ret;
316    }
317    
318    static char *shellEscape(const char *s)
319    {
320        int l = strlen(s) + sPopCount(s, "'") * 2;
321    
322        char *ret = calloc(l+1, sizeof (*ret));
323        if (!ret)
324     return NULL;
325        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
326     if (s[i] == '\'')
327        ret[j++] = '\\';
328     ret[j] = s[i];
329        }
330        return ret;
331    }
332    
333    static void unquote(char *s)
334    {
335        int l = strlen(s);
336    
337        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
338     memmove(s, s+1, l-2);
339     s[l-2] = '\0';
340        }
341    }
342    
343    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
344    {
345        char *s = NULL;
346        int rc = 0;
347        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
348    
349        unquote(value);
350        value = shellEscape(value);
351        if (!value)
352        return -1;
353    
354        rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value);
355        free(value);
356        if (rc <0)
357     return -1;
358    
359        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
360        rc = system(s);
361        free(s);
362        return rc;
363    }
364    
365    /* this is a gigantic hack to avoid clobbering grub2 variables... */
366    static int is_special_grub2_variable(const char *name)
367    {
368        if (!strcmp(name,"\"${next_entry}\""))
369     return 1;
370        if (!strcmp(name,"\"${prev_saved_entry}\""))
371     return 1;
372        return 0;
373    }
374    
375    int sizeOfSingleLine(struct singleLine * line) {
376      int count = 0;
377    
378      for (int i = 0; i < line->numElements; i++) {
379        int indentSize = 0;
380    
381        count = count + strlen(line->elements[i].item);
382    
383        indentSize = strlen(line->elements[i].indent);
384        if (indentSize > 0)
385          count = count + indentSize;
386        else
387          /* be extra safe and add room for whitespaces */
388          count = count + 1;
389      }
390    
391      /* room for trailing terminator */
392      count = count + 1;
393    
394      return count;
395    }
396    
397    static int isquote(char q)
398    {
399        if (q == '\'' || q == '\"')
400     return 1;
401        return 0;
402    }
403    
404    static int iskernel(enum lineType_e type) {
405        return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
406    }
407    
408    static int isinitrd(enum lineType_e type) {
409        return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
410    }
411    
412    char *grub2ExtractTitle(struct singleLine * line) {
413        char * current;
414        char * current_indent;
415        int current_len;
416        int current_indent_len;
417        int i;
418    
419        /* bail out if line does not start with menuentry */
420        if (strcmp(line->elements[0].item, "menuentry"))
421          return NULL;
422    
423        i = 1;
424        current = line->elements[i].item;
425        current_len = strlen(current);
426    
427        /* if second word is quoted, strip the quotes and return single word */
428        if (isquote(*current) && isquote(current[current_len - 1])) {
429     char *tmp;
430    
431     tmp = strdup(current);
432     *(tmp + current_len - 1) = '\0';
433     return ++tmp;
434        }
435    
436        /* if no quotes, return second word verbatim */
437        if (!isquote(*current))
438     return current;
439    
440        /* second element start with a quote, so we have to find the element
441         * whose last character is also quote (assuming it's the closing one) */
442        int resultMaxSize;
443        char * result;
444        
445        resultMaxSize = sizeOfSingleLine(line);
446        result = malloc(resultMaxSize);
447        snprintf(result, resultMaxSize, "%s", ++current);
448        
449        i++;
450        for (; i < line->numElements; ++i) {
451     current = line->elements[i].item;
452     current_len = strlen(current);
453     current_indent = line->elements[i].indent;
454     current_indent_len = strlen(current_indent);
455    
456     strncat(result, current_indent, current_indent_len);
457     if (!isquote(current[current_len-1])) {
458        strncat(result, current, current_len);
459     } else {
460        strncat(result, current, current_len - 1);
461        break;
462     }
463        }
464        return result;
465    }
466    
467    struct configFileInfo grub2ConfigType = {
468        .findConfig = grub2FindConfig,
469        .getEnv = grub2GetEnv,
470        .setEnv = grub2SetEnv,
471        .keywords = grub2Keywords,
472        .defaultIsIndex = 1,
473        .defaultSupportSaved = 1,
474        .defaultIsVariable = 1,
475        .entryStart = LT_MENUENTRY,
476        .entryEnd = LT_ENTRY_END,
477        .titlePosition = 1,
478        .needsBootPrefix = 1,
479        .mbHyperFirst = 1,
480        .mbInitRdIsModule = 1,
481        .mbAllowExtraInitRds = 1,
482  };  };
483    
484  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 512  struct keywordTypes yabootKeywords[] = {
512      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
513      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
514      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
515      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
516      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
517      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
518      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 532  struct keywordTypes liloKeywords[] = {
532      { NULL,    0, 0 },      { NULL,    0, 0 },
533  };  };
534    
535    struct keywordTypes eliloKeywords[] = {
536        { "label",    LT_TITLE,    '=' },
537        { "root",    LT_ROOT,    '=' },
538        { "default",    LT_DEFAULT,    '=' },
539        { "image",    LT_KERNEL,    '=' },
540        { "initrd",    LT_INITRD,    '=' },
541        { "append",    LT_KERNELARGS,  '=' },
542        { "vmm",    LT_HYPER,       '=' },
543        { NULL,    0, 0 },
544    };
545    
546  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
547      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
548      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 564  struct keywordTypes ziplKeywords[] = {
564      { NULL,         0, 0 },      { NULL,         0, 0 },
565  };  };
566    
567    struct keywordTypes extlinuxKeywords[] = {
568        { "label",    LT_TITLE,    ' ' },
569        { "root",    LT_ROOT,    ' ' },
570        { "default",    LT_DEFAULT,    ' ' },
571        { "kernel",    LT_KERNEL,    ' ' },
572        { "initrd",    LT_INITRD,      ' ', ',' },
573        { "append",    LT_KERNELARGS,  ' ' },
574        { "prompt",     LT_UNKNOWN,     ' ' },
575        { NULL,    0, 0 },
576    };
577    int useextlinuxmenu;
578  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
579      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
580      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
581      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
582      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
583      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
584      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
585  };  };
586    
587  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
588      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
589      liloKeywords,    /* keywords */      .keywords = liloKeywords,
590      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
591      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
592      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
593  };  };
594    
595  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
596      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
597      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
598      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
599      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
600      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
601      1,    /* needsBootPrefix */      .maxTitleLength = 15,
602      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
603  };  };
604    
605  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
606      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
607      siloKeywords,    /* keywords */      .keywords = siloKeywords,
608      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
609      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
610      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
611      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
612  };  };
613    
614  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
615      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
616      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
617      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
618      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
619      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
620      0,    /* needsBootPrefix */  };
621      1,    /* argsInQuotes */  
622      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
623      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
624        .keywords = extlinuxKeywords,
625        .caseInsensitive = 1,
626        .entryStart = LT_TITLE,
627        .needsBootPrefix = 1,
628        .maxTitleLength = 255,
629        .mbAllowExtraInitRds = 1,
630  };  };
631    
632  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 641  struct grubConfig {
641      struct configFileInfo * cfi;      struct configFileInfo * cfi;
642  };  };
643    
644    blkid_cache blkid;
645    
646  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
647  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
648       const char * path, const char * prefix,       const char * path, const char * prefix,
649       int * index);       int * index);
650  static char * strndup(char * from, int len);  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
651          int * index);
652  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
653  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
654    struct singleLine * lineDup(struct singleLine * line);
655  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
656  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
657       struct configFileInfo * cfi);       struct configFileInfo * cfi);
658  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
659         struct configFileInfo * cfi);         struct configFileInfo * cfi);
660  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
661    static void requote(struct singleLine *line, struct configFileInfo * cfi);
662  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
663      char * to;    const char * item, int insertHere,
664      struct configFileInfo * cfi);
665      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
666      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
667      to[len] = '\0';        struct configFileInfo * cfi);
668    static enum lineType_e getTypeByKeyword(char * keyword,
669      return to;   struct configFileInfo * cfi);
670  }  static struct singleLine * getLineByType(enum lineType_e type,
671     struct singleLine * line);
672    static int checkForExtLinux(struct grubConfig * config);
673    struct singleLine * addLineTmpl(struct singleEntry * entry,
674                                    struct singleLine * tmplLine,
675                                    struct singleLine * prevLine,
676                                    const char * val,
677     struct configFileInfo * cfi);
678    struct singleLine *  addLine(struct singleEntry * entry,
679                                 struct configFileInfo * cfi,
680                                 enum lineType_e type, char * defaultIndent,
681                                 const char * val);
682    
683  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
684  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 713  static char * sdupprintf(const char *for
713      return buf;      return buf;
714  }  }
715    
716    static enum lineType_e preferredLineType(enum lineType_e type,
717     struct configFileInfo *cfi) {
718        if (isEfi && cfi == &grub2ConfigType) {
719     switch (type) {
720     case LT_KERNEL:
721        return LT_KERNEL_EFI;
722     case LT_INITRD:
723        return LT_INITRD_EFI;
724     default:
725        return type;
726     }
727    #if defined(__i386__) || defined(__x86_64__)
728        } else if (cfi == &grub2ConfigType) {
729     switch (type) {
730     case LT_KERNEL:
731        return LT_KERNEL_16;
732     case LT_INITRD:
733        return LT_INITRD_16;
734     default:
735        return type;
736     }
737    #endif
738        }
739        return type;
740    }
741    
742    static struct keywordTypes * getKeywordByType(enum lineType_e type,
743          struct configFileInfo * cfi) {
744        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
745     if (kw->type == type)
746        return kw;
747        }
748        return NULL;
749    }
750    
751    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
752        struct keywordTypes *kt = getKeywordByType(type, cfi);
753        if (kt)
754     return kt->key;
755        return "unknown";
756    }
757    
758    static char * getpathbyspec(char *device) {
759        if (!blkid)
760            blkid_get_cache(&blkid, NULL);
761    
762        return blkid_get_devname(blkid, device, NULL);
763    }
764    
765    static char * getuuidbydev(char *device) {
766        if (!blkid)
767     blkid_get_cache(&blkid, NULL);
768    
769        return blkid_get_tag_value(blkid, "UUID", device);
770    }
771    
772    static enum lineType_e getTypeByKeyword(char * keyword,
773     struct configFileInfo * cfi) {
774        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
775     if (cfi->caseInsensitive) {
776        if (!strcasecmp(keyword, kw->key))
777                    return kw->type;
778     } else {
779        if (!strcmp(keyword, kw->key))
780            return kw->type;
781     }
782        }
783        return LT_UNKNOWN;
784    }
785    
786    static struct singleLine * getLineByType(enum lineType_e type,
787     struct singleLine * line) {
788        dbgPrintf("getLineByType(%d): ", type);
789        for (; line; line = line->next) {
790     dbgPrintf("%d:%s ", line->type,
791      line->numElements ? line->elements[0].item : "(empty)");
792     if (line->type & type) break;
793        }
794        dbgPrintf(line ? "\n" : " (failed)\n");
795        return line;
796    }
797    
798  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
799      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
800          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
801          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
802              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 808  static int isBracketedTitle(struct singl
808      return 0;      return 0;
809  }  }
810    
811  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
812                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
813      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
814   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;  
815  }  }
816    
817  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
818  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
819      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
820      char * title;      char * title = NULL;
821      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
822      title++;   title = strdup(line->elements[0].item);
823      *(title + strlen(title) - 1) = '\0';   title++;
824     *(title + strlen(title) - 1) = '\0';
825        } else if (line->type == LT_MENUENTRY)
826     title = strdup(line->elements[1].item);
827        else
828     return NULL;
829      return title;      return title;
830  }  }
831    
# Line 389  static void lineInit(struct singleLine * Line 867  static void lineInit(struct singleLine *
867      line->next = NULL;      line->next = NULL;
868  }  }
869    
870  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
871      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
872    
873        newLine->indent = strdup(line->indent);
874        newLine->next = NULL;
875        newLine->type = line->type;
876        newLine->numElements = line->numElements;
877        newLine->elements = malloc(sizeof(*newLine->elements) *
878           newLine->numElements);
879    
880        for (int i = 0; i < newLine->numElements; i++) {
881     newLine->elements[i].indent = strdup(line->elements[i].indent);
882     newLine->elements[i].item = strdup(line->elements[i].item);
883        }
884    
885        return newLine;
886    }
887    
888    static void lineFree(struct singleLine * line) {
889      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
890    
891      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
892   free(line->elements[i].item);   free(line->elements[i].item);
893   free(line->elements[i].indent);   free(line->elements[i].indent);
894      }      }
# Line 405  static void lineFree(struct singleLine * Line 899  static void lineFree(struct singleLine *
899    
900  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
901       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
902      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
903    
904      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
905     /* Need to handle this, because we strip the quotes from
906     * menuentry when read it. */
907     if (line->type == LT_MENUENTRY && i == 1) {
908        if(!isquote(*line->elements[i].item))
909     fprintf(out, "\'%s\'", line->elements[i].item);
910        else
911     fprintf(out, "%s", line->elements[i].item);
912        fprintf(out, "%s", line->elements[i].indent);
913    
914        continue;
915     }
916    
917   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
918      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
919    
920   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
921   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
922        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
923      }      }
924    
925      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 938  static int getNextLine(char ** bufPtr, s
938      char * chptr;      char * chptr;
939      int elementsAlloced = 0;      int elementsAlloced = 0;
940      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
941      int first = 1;      int first = 1;
     int i;  
942    
943      lineFree(line);      lineFree(line);
944    
# Line 489  static int getNextLine(char ** bufPtr, s Line 992  static int getNextLine(char ** bufPtr, s
992      if (!line->numElements)      if (!line->numElements)
993   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
994      else {      else {
995   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
996      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;  
               
997              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
998               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
999              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 1007  static int getNextLine(char ** bufPtr, s
1007      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
1008   char * fullLine;   char * fullLine;
1009   int len;   int len;
  int i;  
1010    
1011   len = strlen(line->indent);   len = strlen(line->indent);
1012   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
1013      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
1014     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1015    
# Line 522  static int getNextLine(char ** bufPtr, s Line 1018  static int getNextLine(char ** bufPtr, s
1018   free(line->indent);   free(line->indent);
1019   line->indent = fullLine;   line->indent = fullLine;
1020    
1021   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1022      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1023      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1024      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 1028  static int getNextLine(char ** bufPtr, s
1028   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
1029   line->numElements = 0;   line->numElements = 0;
1030      }      }
1031     } else {
1032     struct keywordTypes *kw;
1033    
1034     kw = getKeywordByType(line->type, cfi);
1035    
1036     /* space isn't the only separator, we need to split
1037     * elements up more
1038     */
1039     if (!isspace(kw->separatorChar)) {
1040        char indent[2] = "";
1041        indent[0] = kw->separatorChar;
1042        for (int i = 1; i < line->numElements; i++) {
1043     char *p;
1044     int numNewElements;
1045    
1046     numNewElements = 0;
1047     p = line->elements[i].item;
1048     while (*p != '\0') {
1049     if (*p == kw->separatorChar)
1050     numNewElements++;
1051     p++;
1052     }
1053     if (line->numElements + numNewElements >= elementsAlloced) {
1054     elementsAlloced += numNewElements + 5;
1055     line->elements = realloc(line->elements,
1056        sizeof(*line->elements) * elementsAlloced);
1057     }
1058    
1059     for (int j = line->numElements; j > i; j--) {
1060     line->elements[j + numNewElements] = line->elements[j];
1061     }
1062     line->numElements += numNewElements;
1063    
1064     p = line->elements[i].item;
1065     while (*p != '\0') {
1066    
1067     while (*p != kw->separatorChar && *p != '\0') p++;
1068     if (*p == '\0') {
1069     break;
1070     }
1071    
1072     line->elements[i + 1].indent = line->elements[i].indent;
1073     line->elements[i].indent = strdup(indent);
1074     *p++ = '\0';
1075     i++;
1076     line->elements[i].item = strdup(p);
1077     }
1078        }
1079     }
1080   }   }
1081      }      }
1082    
1083      return 0;      return 0;
1084  }  }
1085    
1086    static int isnumber(const char *s)
1087    {
1088        int i;
1089        for (i = 0; s[i] != '\0'; i++)
1090     if (s[i] < '0' || s[i] > '9')
1091        return 0;
1092        return i;
1093    }
1094    
1095  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1096        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1097      int in;      int in;
# Line 549  static struct grubConfig * readConfig(co Line 1103  static struct grubConfig * readConfig(co
1103      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1104      char * end;      char * end;
1105      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1106      int i, len;      int len;
1107      char * buf;      char * buf;
1108    
1109      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1110            printf("Could not find bootloader configuration\n");
1111            exit(1);
1112        } else if (!strcmp(inName, "-")) {
1113   in = 0;   in = 0;
1114      } else {      } else {
1115   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1152  static struct grubConfig * readConfig(co
1152      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1153   }   }
1154    
1155   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1156      sawEntry = 1;      sawEntry = 1;
1157      if (!entry) {      if (!entry) {
1158   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1168  static struct grubConfig * readConfig(co
1168      entry->next = NULL;      entry->next = NULL;
1169   }   }
1170    
1171   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1172        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1173        dbgPrintf("%s", line->indent);
1174        for (int i = 0; i < line->numElements; i++)
1175     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1176        dbgPrintf("\n");
1177        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1178        if (kwType && line->numElements == 3 &&
1179        !strcmp(line->elements[1].item, kwType->key) &&
1180        !is_special_grub2_variable(line->elements[2].item)) {
1181     dbgPrintf("Line sets default config\n");
1182     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1183     defaultLine = line;
1184        }
1185     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1186      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1187      defaultLine = line;      defaultLine = line;
1188    
1189            } else if (iskernel(line->type)) {
1190        /* if by some freak chance this is multiboot and the "module"
1191         * lines came earlier in the template, make sure to use LT_HYPER
1192         * instead of LT_KERNEL now
1193         */
1194        if (entry->multiboot)
1195     line->type = LT_HYPER;
1196    
1197          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1198        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1199         * instead, now that we know this is a multiboot entry.
1200         * This only applies to grub, but that's the only place we
1201         * should find LT_MBMODULE lines anyway.
1202         */
1203        for (struct singleLine *l = entry->lines; l; l = l->next) {
1204     if (l->type == LT_HYPER)
1205        break;
1206     else if (iskernel(l->type)) {
1207        l->type = LT_HYPER;
1208        break;
1209     }
1210        }
1211              entry->multiboot = 1;              entry->multiboot = 1;
1212    
1213     } else if (line->type == LT_HYPER) {
1214        entry->multiboot = 1;
1215    
1216   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1217      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1218      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1219    
1220   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1221      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1222      len = 0;      len = 0;
1223      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1224   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1225   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1226      }      }
1227      buf = malloc(len + 1);      buf = malloc(len + 1);
1228      *buf = '\0';      *buf = '\0';
1229    
1230      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1231   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1232   free(line->elements[i].item);   free(line->elements[i].item);
1233    
# Line 643  static struct grubConfig * readConfig(co Line 1241  static struct grubConfig * readConfig(co
1241      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1242      line->elements[1].item = buf;      line->elements[1].item = buf;
1243      line->numElements = 2;      line->numElements = 2;
1244     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1245        /* let --remove-kernel="TITLE=what" work */
1246        len = 0;
1247        char *extras;
1248        char *title;
1249    
1250        for (int i = 1; i < line->numElements; i++) {
1251     len += strlen(line->elements[i].item);
1252     len += strlen(line->elements[i].indent);
1253        }
1254        buf = malloc(len + 1);
1255        *buf = '\0';
1256    
1257        /* allocate mem for extra flags. */
1258        extras = malloc(len + 1);
1259        *extras = '\0';
1260    
1261        /* get title. */
1262        for (int i = 0; i < line->numElements; i++) {
1263     if (!strcmp(line->elements[i].item, "menuentry"))
1264        continue;
1265     if (isquote(*line->elements[i].item))
1266        title = line->elements[i].item + 1;
1267     else
1268        title = line->elements[i].item;
1269    
1270     len = strlen(title);
1271            if (isquote(title[len-1])) {
1272        strncat(buf, title,len-1);
1273        break;
1274     } else {
1275        strcat(buf, title);
1276        strcat(buf, line->elements[i].indent);
1277     }
1278        }
1279    
1280        /* get extras */
1281        int count = 0;
1282        for (int i = 0; i < line->numElements; i++) {
1283     if (count >= 2) {
1284        strcat(extras, line->elements[i].item);
1285        strcat(extras, line->elements[i].indent);
1286     }
1287    
1288     if (!strcmp(line->elements[i].item, "menuentry"))
1289        continue;
1290    
1291     /* count ' or ", there should be two in menuentry line. */
1292     if (isquote(*line->elements[i].item))
1293        count++;
1294    
1295     len = strlen(line->elements[i].item);
1296    
1297     if (isquote(line->elements[i].item[len -1]))
1298        count++;
1299    
1300     /* ok, we get the final ' or ", others are extras. */
1301                }
1302        line->elements[1].indent =
1303     line->elements[line->numElements - 2].indent;
1304        line->elements[1].item = buf;
1305        line->elements[2].indent =
1306     line->elements[line->numElements - 2].indent;
1307        line->elements[2].item = extras;
1308        line->numElements = 3;
1309   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1310      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1311         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 1314  static struct grubConfig * readConfig(co
1314      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1315   int last, len;   int last, len;
1316    
1317   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1318      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1319     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1320    
1321   last = line->numElements - 1;   last = line->numElements - 1;
1322   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1323   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1324      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1325      }      }
   
1326   }   }
1327    
1328   /* 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 1342  static struct grubConfig * readConfig(co
1342   movedLine = 1;   movedLine = 1;
1343   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1344   }   }
1345    
1346   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1347     which was moved, drop it. */     which was moved, drop it. */
1348   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 1358  static struct grubConfig * readConfig(co
1358   entry->lines = line;   entry->lines = line;
1359      else      else
1360   last->next = line;   last->next = line;
1361        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1362    
1363        /* we could have seen this outside of an entry... if so, we
1364         * ignore it like any other line we don't grok */
1365        if (line->type == LT_ENTRY_END && sawEntry)
1366     sawEntry = 0;
1367   } else {   } else {
1368      if (!cfg->theLines)      if (!cfg->theLines)
1369   cfg->theLines = line;   cfg->theLines = line;
1370      else {      else
1371   last->next = line;   last->next = line;
1372      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1373   }   }
1374    
1375   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1377  static struct grubConfig * readConfig(co
1377    
1378      free(incoming);      free(incoming);
1379    
1380        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1381      if (defaultLine) {      if (defaultLine) {
1382   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1383        cfi->defaultSupportSaved &&
1384        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1385     cfg->cfi->defaultIsSaved = 1;
1386     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1387     if (cfg->cfi->getEnv) {
1388        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1389        if (defTitle) {
1390     int index = 0;
1391     if (isnumber(defTitle)) {
1392        index = atoi(defTitle);
1393        entry = findEntryByIndex(cfg, index);
1394     } else {
1395        entry = findEntryByTitle(cfg, defTitle, &index);
1396     }
1397     if (entry)
1398        cfg->defaultImage = index;
1399        }
1400     }
1401     } else if (cfi->defaultIsVariable) {
1402        char *value = defaultLine->elements[2].item;
1403        while (*value && (*value == '"' || *value == '\'' ||
1404        *value == ' ' || *value == '\t'))
1405     value++;
1406        cfg->defaultImage = strtol(value, &end, 10);
1407        while (*end && (*end == '"' || *end == '\'' ||
1408        *end == ' ' || *end == '\t'))
1409     end++;
1410        if (*end) cfg->defaultImage = -1;
1411     } else if (cfi->defaultSupportSaved &&
1412   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1413      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1414   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1415      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1416      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1417   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1418      i = 0;      int i = 0;
1419      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1420   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1421      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1429  static struct grubConfig * readConfig(co
1429                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1430                  }                  }
1431   i++;   i++;
1432     entry = NULL;
1433      }      }
1434    
1435      if (entry) cfg->defaultImage = i;      if (entry){
1436            cfg->defaultImage = i;
1437        }else{
1438            cfg->defaultImage = -1;
1439        }
1440     }
1441        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1442     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1443     if (defTitle) {
1444        int index = 0;
1445        if (isnumber(defTitle)) {
1446     index = atoi(defTitle);
1447     entry = findEntryByIndex(cfg, index);
1448        } else {
1449     entry = findEntryByTitle(cfg, defTitle, &index);
1450        }
1451        if (entry)
1452     cfg->defaultImage = index;
1453   }   }
1454        } else {
1455            cfg->defaultImage = 0;
1456      }      }
1457    
1458      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1468  static void writeDefault(FILE * out, cha
1468    
1469      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1470   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1471      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1472     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1473     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1474        char *title;
1475        entry = findEntryByIndex(cfg, cfg->defaultImage);
1476        line = getLineByType(LT_MENUENTRY, entry->lines);
1477        if (!line)
1478     line = getLineByType(LT_TITLE, entry->lines);
1479        if (line) {
1480     title = extractTitle(line);
1481     if (title)
1482        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1483        }
1484     }
1485        } else if (cfg->defaultImage > -1) {
1486   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1487      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1488      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1489     cfg->defaultImage);
1490        } else {
1491     fprintf(out, "%sdefault%s%d\n", indent, separator,
1492     cfg->defaultImage);
1493        }
1494   } else {   } else {
1495      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1496    
# Line 769  static void writeDefault(FILE * out, cha Line 1507  static void writeDefault(FILE * out, cha
1507    
1508      if (!entry) return;      if (!entry) return;
1509    
1510      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1511    
1512      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1513   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1541  static int writeConfig(struct grubConfig
1541      int rc;      int rc;
1542    
1543      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1544         directory to / */         directory to the dir of the symlink */
1545      rc = chdir("/");      char *dir = strdupa(outName);
1546        rc = chdir(dirname(dir));
1547      do {      do {
1548   buf = alloca(len + 1);   buf = alloca(len + 1);
1549   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1550   if (rc == len) len += 256;   if (rc == len) len += 256;
1551      } while (rc == len);      } while (rc == len);
1552            
# Line 843  static int writeConfig(struct grubConfig Line 1581  static int writeConfig(struct grubConfig
1581      }      }
1582    
1583      line = cfg->theLines;      line = cfg->theLines;
1584        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1585      while (line) {      while (line) {
1586   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1587     line->numElements == 3 &&
1588     !strcmp(line->elements[1].item, defaultKw->key) &&
1589     !is_special_grub2_variable(line->elements[2].item)) {
1590        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1591        needs &= ~MAIN_DEFAULT;
1592     } else if (line->type == LT_DEFAULT) {
1593      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1594      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1595   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1657  static int numEntries(struct grubConfig
1657      return i;      return i;
1658  }  }
1659    
1660  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1661    int skipRemoved, int flags) {  {
1662      struct singleLine * line;      int fd;
1663      char * fullName;      char buf[65536];
1664      int i;      char *devname;
1665      struct stat sb, sb2;      char *chptr;
1666      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1667    
1668      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1669      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1670                        _PATH_MOUNTED, strerror(errno));
1671      if (!line) return 0;          return NULL;
1672      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1673    
1674      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1675        if (rc <= 0) {
1676            fprintf(stderr, "grubby: failed to read %s: %s\n",
1677                    _PATH_MOUNTED, strerror(errno));
1678            close(fd);
1679            return NULL;
1680        }
1681        close(fd);
1682        buf[rc] = '\0';
1683        chptr = buf;
1684    
1685      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;  
1686    
1687      for (i = 2; i < line->numElements; i++)      while (chptr && chptr != buf+rc) {
1688            devname = chptr;
1689    
1690            /*
1691             * The first column of a mtab entry is the device, but if the entry is a
1692             * special device it won't start with /, so move on to the next line.
1693             */
1694            if (*devname != '/') {
1695                chptr = strchr(chptr, '\n');
1696                if (chptr)
1697                    chptr++;
1698                continue;
1699            }
1700    
1701            /* Seek to the next space */
1702            chptr = strchr(chptr, ' ');
1703            if (!chptr) {
1704                fprintf(stderr, "grubby: error parsing %s: %s\n",
1705                        _PATH_MOUNTED, strerror(errno));
1706                return NULL;
1707            }
1708    
1709            /*
1710             * The second column of a mtab entry is the mount point, we are looking
1711             * for '/' obviously.
1712             */
1713            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1714                /* remember the last / entry in mtab */
1715               foundanswer = devname;
1716            }
1717    
1718            /* Next line */
1719            chptr = strchr(chptr, '\n');
1720            if (chptr)
1721                chptr++;
1722        }
1723    
1724        /* Return the last / entry found */
1725        if (foundanswer) {
1726            chptr = strchr(foundanswer, ' ');
1727            *chptr = '\0';
1728            return strdup(foundanswer);
1729        }
1730    
1731        return NULL;
1732    }
1733    
1734    void printEntry(struct singleEntry * entry, FILE *f) {
1735        int i;
1736        struct singleLine * line;
1737    
1738        for (line = entry->lines; line; line = line->next) {
1739     log_message(f, "DBG: %s", line->indent);
1740     for (i = 0; i < line->numElements; i++) {
1741        /* Need to handle this, because we strip the quotes from
1742         * menuentry when read it. */
1743        if (line->type == LT_MENUENTRY && i == 1) {
1744     if(!isquote(*line->elements[i].item))
1745        log_message(f, "\'%s\'", line->elements[i].item);
1746     else
1747        log_message(f, "%s", line->elements[i].item);
1748     log_message(f, "%s", line->elements[i].indent);
1749    
1750     continue;
1751        }
1752        
1753        log_message(f, "%s%s",
1754        line->elements[i].item, line->elements[i].indent);
1755     }
1756     log_message(f, "\n");
1757        }
1758    }
1759    
1760    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1761    {
1762        static int once;
1763        va_list argp, argq;
1764    
1765        va_start(argp, fmt);
1766    
1767        va_copy(argq, argp);
1768        if (!once) {
1769     log_time(NULL);
1770     log_message(NULL, "command line: %s\n", saved_command_line);
1771        }
1772        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1773        log_vmessage(NULL, fmt, argq);
1774    
1775        printEntry(entry, NULL);
1776        va_end(argq);
1777    
1778        if (!debug) {
1779     once = 1;
1780         va_end(argp);
1781     return;
1782        }
1783    
1784        if (okay) {
1785     va_end(argp);
1786     return;
1787        }
1788    
1789        if (!once)
1790     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1791        once = 1;
1792        fprintf(stderr, "DBG: Image entry failed: ");
1793        vfprintf(stderr, fmt, argp);
1794        printEntry(entry, stderr);
1795        va_end(argp);
1796    }
1797    
1798    #define beginswith(s, c) ((s) && (s)[0] == (c))
1799    
1800    static int endswith(const char *s, char c)
1801    {
1802     int slen;
1803    
1804     if (!s || !s[0])
1805     return 0;
1806     slen = strlen(s) - 1;
1807    
1808     return s[slen] == c;
1809    }
1810    
1811    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1812      int skipRemoved, int flags) {
1813        struct singleLine * line;
1814        char * fullName;
1815        int i;
1816        char * dev;
1817        char * rootspec;
1818        char * rootdev;
1819    
1820        if (skipRemoved && entry->skip) {
1821     notSuitablePrintf(entry, 0, "marked to skip\n");
1822     return 0;
1823        }
1824    
1825        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1826        if (!line) {
1827     notSuitablePrintf(entry, 0, "no line found\n");
1828     return 0;
1829        }
1830        if (line->numElements < 2) {
1831     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1832        line->numElements);
1833     return 0;
1834        }
1835    
1836        if (flags & GRUBBY_BADIMAGE_OKAY) {
1837        notSuitablePrintf(entry, 1, "\n");
1838        return 1;
1839        }
1840    
1841        fullName = alloca(strlen(bootPrefix) +
1842          strlen(line->elements[1].item) + 1);
1843        rootspec = getRootSpecifier(line->elements[1].item);
1844        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1845        int hasslash = endswith(bootPrefix, '/') ||
1846         beginswith(line->elements[1].item + rootspec_offset, '/');
1847        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1848                line->elements[1].item + rootspec_offset);
1849        if (access(fullName, R_OK)) {
1850     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1851     return 0;
1852        }
1853        for (i = 2; i < line->numElements; i++)
1854   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1855      if (i < line->numElements) {      if (i < line->numElements) {
1856   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1857      } else {      } else {
1858   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1859   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1860    
1861   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1862      dev = line->elements[1].item;      dev = line->elements[1].item;
1863   } else {   } else {
1864              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1865      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */       * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1866      line = entry->lines;       */
1867        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1868    
1869              /* failed to find one */              /* failed to find one */
1870              if (!line) return 0;              if (!line) {
1871     notSuitablePrintf(entry, 0, "no line found\n");
1872     return 0;
1873                }
1874    
1875      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1876          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1877      if (i < line->numElements)      if (i < line->numElements)
1878          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1879      else {      else {
1880     notSuitablePrintf(entry, 0, "no root= entry found\n");
1881   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1882          return 0;          return 0;
1883              }              }
1884   }   }
1885      }      }
1886    
1887      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1888   dev += 6;      if (!getpathbyspec(dev)) {
1889            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1890   /* check which device has this label */          return 0;
1891   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1892   if (!dev) return 0;   dev = getpathbyspec(dev);
1893    
1894        rootdev = findDiskForRoot();
1895        if (!rootdev) {
1896            notSuitablePrintf(entry, 0, "can't find root device\n");
1897     return 0;
1898      }      }
1899    
1900      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1901   if (stat(dev, &sb))          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1902      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1903      } else {          free(rootdev);
1904   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1905   if (*end) return 0;      }
1906    
1907        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1908            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1909     getuuidbydev(rootdev), getuuidbydev(dev));
1910     free(rootdev);
1911            return 0;
1912      }      }
     stat("/", &sb2);  
1913    
1914      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1915        notSuitablePrintf(entry, 1, "\n");
1916    
1917      return 1;      return 1;
1918  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1956  struct singleEntry * findEntryByPath(str
1956   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1957   if (!entry) return NULL;   if (!entry) return NULL;
1958    
1959   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1960   if (!line) return NULL;   if (!line) return NULL;
1961    
1962   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1994  struct singleEntry * findEntryByPath(str
1994    
1995   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1996      prefix = "";      prefix = "";
1997      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1998      kernel += 6;      kernel += 6;
1999   }   }
2000    
2001   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
2002      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
2003    
2004        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
2005    
2006      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
2007                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
2008          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
2009                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
2010                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2011                      break;   else if (checkType & LT_KERNEL)
2012              }      ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2013                 line = getLineByType(ct, line);
2014              /* have to check multiboot lines too */   if (!line)
2015              if (entry->multiboot) {      break;  /* not found in this entry */
2016                  while (line && line->type != LT_MBMODULE) line = line->next;  
2017                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
2018                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
2019                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
2020                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
2021                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
2022                          break;   kernel + strlen(prefix)))
2023                  }   break;
2024              }   }
2025     if(line->type == LT_MENUENTRY &&
2026     !strcmp(line->elements[1].item, kernel))
2027        break;
2028        }
2029    
2030      i++;      /* make sure this entry has a kernel identifier; this skips
2031         * non-Linux boot entries (could find netbsd etc, though, which is
2032         * unfortunate)
2033         */
2034        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2035     break; /* found 'im! */
2036   }   }
2037    
2038   if (index) *index = i;   if (index) *index = i;
2039      }      }
2040    
2041      if (!entry) return NULL;      return entry;
2042    }
2043    
2044      /* make sure this entry has a kernel identifier; this skips non-Linux  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2045         boot entries (could find netbsd etc, though, which is unfortunate) */        int * index) {
2046      line = entry->lines;      struct singleEntry * entry;
2047      while (line && line->type != LT_KERNEL) line = line->next;      struct singleLine * line;
2048      if (!line) {      int i;
2049   if (!index) index = &i;      char * newtitle;
2050   (*index)++;  
2051   return findEntryByPath(config, kernel, prefix, index);      for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2052     if (index && i < *index)
2053        continue;
2054     line = getLineByType(LT_TITLE, entry->lines);
2055     if (!line)
2056        line = getLineByType(LT_MENUENTRY, entry->lines);
2057     if (!line)
2058        continue;
2059     newtitle = grub2ExtractTitle(line);
2060     if (!newtitle)
2061        continue;
2062     if (!strcmp(title, newtitle))
2063        break;
2064      }      }
2065    
2066        if (!entry)
2067     return NULL;
2068    
2069        if (index)
2070     *index = i;
2071      return entry;      return entry;
2072  }  }
2073    
# Line 1147  struct singleEntry * findTemplate(struct Line 2093  struct singleEntry * findTemplate(struct
2093      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2094      int index;      int index;
2095    
2096      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2097     if (cfg->cfi->getEnv) {
2098        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2099        if (defTitle) {
2100     int index = 0;
2101     if (isnumber(defTitle)) {
2102        index = atoi(defTitle);
2103        entry = findEntryByIndex(cfg, index);
2104     } else {
2105        entry = findEntryByTitle(cfg, defTitle, &index);
2106     }
2107     if (entry)
2108        cfg->defaultImage = index;
2109        }
2110     }
2111        } else if (cfg->defaultImage > -1) {
2112   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2113   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2114      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1200  void markRemovedImage(struct grubConfig Line 2161  void markRemovedImage(struct grubConfig
2161        const char * prefix) {        const char * prefix) {
2162      struct singleEntry * entry;      struct singleEntry * entry;
2163    
2164      if (!image) return;      if (!image)
2165     return;
2166    
2167        /* check and see if we're removing the default image */
2168        if (isdigit(*image)) {
2169     entry = findEntryByPath(cfg, image, prefix, NULL);
2170     if(entry)
2171        entry->skip = 1;
2172     return;
2173        }
2174    
2175      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2176   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 2178  void markRemovedImage(struct grubConfig
2178    
2179  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2180       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2181       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2182      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2183      int i, j;      int i, j;
2184    
2185      if (newIsDefault) {      if (newIsDefault) {
2186   config->defaultImage = 0;   config->defaultImage = 0;
2187   return;   return;
2188        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2189     if (findEntryByIndex(config, index))
2190        config->defaultImage = index;
2191     else
2192        config->defaultImage = -1;
2193     return;
2194      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2195   i = 0;   i = 0;
2196   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 2203  void setDefaultImage(struct grubConfig *
2203    
2204      /* 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
2205         changes */         changes */
2206      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2207     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2208        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2209        return;        return;
2210    
# Line 1286  void displayEntry(struct singleEntry * e Line 2263  void displayEntry(struct singleEntry * e
2263      char * root = NULL;      char * root = NULL;
2264      int i;      int i;
2265    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2266      printf("index=%d\n", index);      printf("index=%d\n", index);
2267    
2268      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2269        if (!line) {
2270            printf("non linux entry\n");
2271            return;
2272        }
2273    
2274        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2275     printf("kernel=%s\n", line->elements[1].item);
2276        else
2277     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2278    
2279      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2280   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2291  void displayEntry(struct singleEntry * e
2291   }   }
2292   printf("\"\n");   printf("\"\n");
2293      } else {      } else {
2294   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2295   if (line) {   if (line) {
2296      char * s;      char * s;
2297    
# Line 1334  void displayEntry(struct singleEntry * e Line 2315  void displayEntry(struct singleEntry * e
2315      }      }
2316    
2317      if (!root) {      if (!root) {
2318   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2319   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2320      root=line->elements[1].item;      root=line->elements[1].item;
2321      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2330  void displayEntry(struct singleEntry * e
2330   printf("root=%s\n", s);   printf("root=%s\n", s);
2331      }      }
2332    
2333      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2334    
2335      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2336   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2337        printf("initrd=");
2338     else
2339        printf("initrd=%s", prefix);
2340    
2341   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2342      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2343   printf("\n");   printf("\n");
2344      }      }
2345    
2346        line = getLineByType(LT_TITLE, entry->lines);
2347        if (line) {
2348     printf("title=%s\n", line->elements[1].item);
2349        } else {
2350     char * title;
2351     line = getLineByType(LT_MENUENTRY, entry->lines);
2352     title = grub2ExtractTitle(line);
2353     if (title)
2354        printf("title=%s\n", title);
2355        }
2356    }
2357    
2358    int isSuseSystem(void) {
2359        const char * path;
2360        const static char default_path[] = "/etc/SuSE-release";
2361    
2362        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2363     path = default_path;
2364    
2365        if (!access(path, R_OK))
2366     return 1;
2367        return 0;
2368    }
2369    
2370    int isSuseGrubConf(const char * path) {
2371        FILE * grubConf;
2372        char * line = NULL;
2373        size_t len = 0, res = 0;
2374    
2375        grubConf = fopen(path, "r");
2376        if (!grubConf) {
2377            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2378     return 0;
2379        }
2380    
2381        while ((res = getline(&line, &len, grubConf)) != -1) {
2382     if (!strncmp(line, "setup", 5)) {
2383        fclose(grubConf);
2384        free(line);
2385        return 1;
2386     }
2387        }
2388    
2389        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2390          path);
2391    
2392        fclose(grubConf);
2393        free(line);
2394        return 0;
2395    }
2396    
2397    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2398        FILE * grubConf;
2399        char * line = NULL;
2400        size_t res = 0, len = 0;
2401    
2402        if (!path) return 1;
2403        if (!lbaPtr) return 1;
2404    
2405        grubConf = fopen(path, "r");
2406        if (!grubConf) return 1;
2407    
2408        while ((res = getline(&line, &len, grubConf)) != -1) {
2409     if (line[res - 1] == '\n')
2410        line[res - 1] = '\0';
2411     else if (len > res)
2412        line[res] = '\0';
2413     else {
2414        line = realloc(line, res + 1);
2415        line[res] = '\0';
2416     }
2417    
2418     if (!strncmp(line, "setup", 5)) {
2419        if (strstr(line, "--force-lba")) {
2420            *lbaPtr = 1;
2421        } else {
2422            *lbaPtr = 0;
2423        }
2424        dbgPrintf("lba: %i\n", *lbaPtr);
2425        break;
2426     }
2427        }
2428    
2429        free(line);
2430        fclose(grubConf);
2431        return 0;
2432    }
2433    
2434    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2435        FILE * grubConf;
2436        char * line = NULL;
2437        size_t res = 0, len = 0;
2438        char * lastParamPtr = NULL;
2439        char * secLastParamPtr = NULL;
2440        char installDeviceNumber = '\0';
2441        char * bounds = NULL;
2442    
2443        if (!path) return 1;
2444        if (!devicePtr) return 1;
2445    
2446        grubConf = fopen(path, "r");
2447        if (!grubConf) return 1;
2448    
2449        while ((res = getline(&line, &len, grubConf)) != -1) {
2450     if (strncmp(line, "setup", 5))
2451        continue;
2452    
2453     if (line[res - 1] == '\n')
2454        line[res - 1] = '\0';
2455     else if (len > res)
2456        line[res] = '\0';
2457     else {
2458        line = realloc(line, res + 1);
2459        line[res] = '\0';
2460     }
2461    
2462     lastParamPtr = bounds = line + res;
2463    
2464     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2465     while (!isspace(*lastParamPtr))
2466        lastParamPtr--;
2467     lastParamPtr++;
2468    
2469     secLastParamPtr = lastParamPtr - 2;
2470     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2471    
2472     if (lastParamPtr + 3 > bounds) {
2473        dbgPrintf("lastParamPtr going over boundary");
2474        fclose(grubConf);
2475        free(line);
2476        return 1;
2477     }
2478     if (!strncmp(lastParamPtr, "(hd", 3))
2479        lastParamPtr += 3;
2480     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2481    
2482     /*
2483     * Second last parameter will decide wether last parameter is
2484     * an IMAGE_DEVICE or INSTALL_DEVICE
2485     */
2486     while (!isspace(*secLastParamPtr))
2487        secLastParamPtr--;
2488     secLastParamPtr++;
2489    
2490     if (secLastParamPtr + 3 > bounds) {
2491        dbgPrintf("secLastParamPtr going over boundary");
2492        fclose(grubConf);
2493        free(line);
2494        return 1;
2495     }
2496     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2497     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2498        secLastParamPtr += 3;
2499        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2500        installDeviceNumber = *secLastParamPtr;
2501     } else {
2502        installDeviceNumber = *lastParamPtr;
2503     }
2504    
2505     *devicePtr = malloc(6);
2506     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2507     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2508     fclose(grubConf);
2509     free(line);
2510     return 0;
2511        }
2512    
2513        free(line);
2514        fclose(grubConf);
2515        return 1;
2516    }
2517    
2518    int grubGetBootFromDeviceMap(const char * device,
2519         char ** bootPtr) {
2520        FILE * deviceMap;
2521        char * line = NULL;
2522        size_t res = 0, len = 0;
2523        char * devicePtr;
2524        char * bounds = NULL;
2525        const char * path;
2526        const static char default_path[] = "/boot/grub/device.map";
2527    
2528        if (!device) return 1;
2529        if (!bootPtr) return 1;
2530    
2531        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2532     path = default_path;
2533    
2534        dbgPrintf("opening grub device.map file from: %s\n", path);
2535        deviceMap = fopen(path, "r");
2536        if (!deviceMap)
2537     return 1;
2538    
2539        while ((res = getline(&line, &len, deviceMap)) != -1) {
2540            if (!strncmp(line, "#", 1))
2541        continue;
2542    
2543     if (line[res - 1] == '\n')
2544        line[res - 1] = '\0';
2545     else if (len > res)
2546        line[res] = '\0';
2547     else {
2548        line = realloc(line, res + 1);
2549        line[res] = '\0';
2550     }
2551    
2552     devicePtr = line;
2553     bounds = line + res;
2554    
2555     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2556        devicePtr++;
2557     dbgPrintf("device: %s\n", devicePtr);
2558    
2559     if (!strncmp(devicePtr, device, strlen(device))) {
2560        devicePtr += strlen(device);
2561        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2562            devicePtr++;
2563    
2564        *bootPtr = strdup(devicePtr);
2565        break;
2566     }
2567        }
2568    
2569        free(line);
2570        fclose(deviceMap);
2571        return 0;
2572    }
2573    
2574    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2575        char * grubDevice;
2576    
2577        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2578     dbgPrintf("error looking for grub installation device\n");
2579        else
2580     dbgPrintf("grubby installation device: %s\n", grubDevice);
2581    
2582        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2583     dbgPrintf("error looking for grub boot device\n");
2584        else
2585     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2586    
2587        free(grubDevice);
2588        return 0;
2589    }
2590    
2591    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2592        /*
2593         * This SuSE grub configuration file at this location is not your average
2594         * grub configuration file, but instead the grub commands used to setup
2595         * grub on that system.
2596         */
2597        const char * path;
2598        const static char default_path[] = "/etc/grub.conf";
2599    
2600        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2601     path = default_path;
2602    
2603        if (!isSuseGrubConf(path)) return 1;
2604    
2605        if (lbaPtr) {
2606            *lbaPtr = 0;
2607            if (suseGrubConfGetLba(path, lbaPtr))
2608                return 1;
2609        }
2610    
2611        if (bootPtr) {
2612            *bootPtr = NULL;
2613            suseGrubConfGetBoot(path, bootPtr);
2614        }
2615    
2616        return 0;
2617  }  }
2618    
2619  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2623  int parseSysconfigGrub(int * lbaPtr, cha
2623      char * start;      char * start;
2624      char * param;      char * param;
2625    
2626      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2627      if (!in) return 1;      if (!in) return 1;
2628    
2629      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2664  int parseSysconfigGrub(int * lbaPtr, cha
2664  }  }
2665    
2666  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2667      char * boot;      char * boot = NULL;
2668      int lba;      int lba;
2669    
2670      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2671   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2672   if (boot) printf("boot=%s\n", boot);      free(boot);
2673        return;
2674     }
2675        } else {
2676            if (parseSysconfigGrub(&lba, &boot)) {
2677        free(boot);
2678        return;
2679     }
2680        }
2681    
2682        if (lba) printf("lba\n");
2683        if (boot) {
2684     printf("boot=%s\n", boot);
2685     free(boot);
2686      }      }
2687  }  }
2688    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2698  int displayInfo(struct grubConfig * conf
2698   return 1;   return 1;
2699      }      }
2700    
2701      /* 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
2702         be a better way */         be a better way */
2703      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2704   dumpSysconfigGrub();   dumpSysconfigGrub();
2705      } else {      } else {
2706   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2707   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2708      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2709   }   }
2710    
2711   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2712   if (line) printf("lba\n");   if (line) printf("lba\n");
2713      }      }
2714    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2723  int displayInfo(struct grubConfig * conf
2723      return 0;      return 0;
2724  }  }
2725    
2726    struct singleLine * addLineTmpl(struct singleEntry * entry,
2727     struct singleLine * tmplLine,
2728     struct singleLine * prevLine,
2729     const char * val,
2730     struct configFileInfo * cfi)
2731    {
2732        struct singleLine * newLine = lineDup(tmplLine);
2733    
2734        if (isEfi && cfi == &grub2ConfigType) {
2735     enum lineType_e old = newLine->type;
2736     newLine->type = preferredLineType(newLine->type, cfi);
2737     if (old != newLine->type)
2738        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2739        }
2740    
2741        if (val) {
2742     /* override the inherited value with our own.
2743     * This is a little weak because it only applies to elements[1]
2744     */
2745     if (newLine->numElements > 1)
2746        removeElement(newLine, 1);
2747     insertElement(newLine, val, 1, cfi);
2748    
2749     /* but try to keep the rootspec from the template... sigh */
2750     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2751        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2752        if (rootspec != NULL) {
2753     free(newLine->elements[1].item);
2754     newLine->elements[1].item =
2755        sdupprintf("%s%s", rootspec, val);
2756        }
2757     }
2758        }
2759    
2760        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2761          newLine->elements[0].item : "");
2762    
2763        if (!entry->lines) {
2764     /* first one on the list */
2765     entry->lines = newLine;
2766        } else if (prevLine) {
2767     /* add after prevLine */
2768     newLine->next = prevLine->next;
2769     prevLine->next = newLine;
2770        }
2771    
2772        return newLine;
2773    }
2774    
2775  /* val may be NULL */  /* val may be NULL */
2776  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2777       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2778       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2779       char * val) {       const char * val) {
2780      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2781      int i;      struct keywordTypes * kw;
2782        struct singleLine tmpl;
2783    
2784      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2785   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2786      if (type != LT_TITLE || !cfi->titleBracketed)       */
2787          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2788     /* we're doing a bracketed title (zipl) */
2789     tmpl.type = type;
2790     tmpl.numElements = 1;
2791     tmpl.elements = alloca(sizeof(*tmpl.elements));
2792     tmpl.elements[0].item = alloca(strlen(val)+3);
2793     sprintf(tmpl.elements[0].item, "[%s]", val);
2794     tmpl.elements[0].indent = "";
2795     val = NULL;
2796        } else if (type == LT_MENUENTRY) {
2797     char *lineend = "--class gnu-linux --class gnu --class os {";
2798     if (!val) {
2799        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2800        abort();
2801     }
2802     kw = getKeywordByType(type, cfi);
2803     if (!kw) {
2804        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2805        abort();
2806     }
2807     tmpl.indent = "";
2808     tmpl.type = type;
2809     tmpl.numElements = 3;
2810     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2811     tmpl.elements[0].item = kw->key;
2812     tmpl.elements[0].indent = alloca(2);
2813     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2814     tmpl.elements[1].item = (char *)val;
2815     tmpl.elements[1].indent = alloca(2);
2816     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2817     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2818     strcpy(tmpl.elements[2].item, lineend);
2819     tmpl.elements[2].indent = "";
2820        } else {
2821     kw = getKeywordByType(type, cfi);
2822     if (!kw) {
2823        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2824        abort();
2825     }
2826     tmpl.type = type;
2827     tmpl.numElements = val ? 2 : 1;
2828     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2829     tmpl.elements[0].item = kw->key;
2830     tmpl.elements[0].indent = alloca(2);
2831     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2832     if (val) {
2833        tmpl.elements[1].item = (char *)val;
2834        tmpl.elements[1].indent = "";
2835     }
2836        }
2837    
2838      /* 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
2839         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2840         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
2841         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2842         differently from the rest) */         differently from the rest) */
2843      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2844   line = entry->lines;   if (line->numElements) prev = line;
2845   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2846   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;  
2847      }      }
2848    
2849      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2850          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2851          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2852          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2853          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2854          line->elements[0].indent = malloc(2);   else
2855          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2856          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2857             if (menuEntry)
2858          if (val) {      tmpl.indent = "\t";
2859              line->elements[1].item = val;   else if (prev == entry->lines)
2860              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2861          }   else
2862      } 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("");  
2863      }      }
2864    
2865      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2866  }  }
2867    
2868  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2887  void removeLine(struct singleEntry * ent
2887      free(line);      free(line);
2888  }  }
2889    
2890    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2891    {
2892        struct singleLine newLine = {
2893     .indent = tmplLine->indent,
2894     .type = tmplLine->type,
2895     .next = tmplLine->next,
2896        };
2897        int firstQuotedItem = -1;
2898        int quoteLen = 0;
2899        int j;
2900        int element = 0;
2901        char *c;
2902    
2903        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2904        strcpy(c, tmplLine->elements[0].item);
2905        insertElement(&newLine, c, element++, cfi);
2906        free(c);
2907        c = NULL;
2908    
2909        for (j = 1; j < tmplLine->numElements; j++) {
2910     if (firstQuotedItem == -1) {
2911        quoteLen += strlen(tmplLine->elements[j].item);
2912        
2913        if (isquote(tmplLine->elements[j].item[0])) {
2914     firstQuotedItem = j;
2915            quoteLen += strlen(tmplLine->elements[j].indent);
2916        } else {
2917     c = malloc(quoteLen + 1);
2918     strcpy(c, tmplLine->elements[j].item);
2919     insertElement(&newLine, c, element++, cfi);
2920     free(c);
2921     quoteLen = 0;
2922        }
2923     } else {
2924        int itemlen = strlen(tmplLine->elements[j].item);
2925        quoteLen += itemlen;
2926        quoteLen += strlen(tmplLine->elements[j].indent);
2927        
2928        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2929     c = malloc(quoteLen + 1);
2930     c[0] = '\0';
2931     for (int i = firstQuotedItem; i < j+1; i++) {
2932        strcat(c, tmplLine->elements[i].item);
2933        strcat(c, tmplLine->elements[i].indent);
2934     }
2935     insertElement(&newLine, c, element++, cfi);
2936     free(c);
2937    
2938     firstQuotedItem = -1;
2939     quoteLen = 0;
2940        }
2941     }
2942        }
2943        while (tmplLine->numElements)
2944     removeElement(tmplLine, 0);
2945        if (tmplLine->elements)
2946     free(tmplLine->elements);
2947    
2948        tmplLine->numElements = newLine.numElements;
2949        tmplLine->elements = newLine.elements;
2950    }
2951    
2952    static void insertElement(struct singleLine * line,
2953      const char * item, int insertHere,
2954      struct configFileInfo * cfi)
2955    {
2956        struct keywordTypes * kw;
2957        char indent[2] = "";
2958    
2959        /* sanity check */
2960        if (insertHere > line->numElements) {
2961     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2962      insertHere, line->numElements);
2963     insertHere = line->numElements;
2964        }
2965    
2966        line->elements = realloc(line->elements, (line->numElements + 1) *
2967         sizeof(*line->elements));
2968        memmove(&line->elements[insertHere+1],
2969        &line->elements[insertHere],
2970        (line->numElements - insertHere) *
2971        sizeof(*line->elements));
2972        line->elements[insertHere].item = strdup(item);
2973    
2974        kw = getKeywordByType(line->type, cfi);
2975    
2976        if (line->numElements == 0) {
2977     indent[0] = '\0';
2978        } else if (insertHere == 0) {
2979     indent[0] = kw->nextChar;
2980        } else if (kw->separatorChar != '\0') {
2981     indent[0] = kw->separatorChar;
2982        } else {
2983     indent[0] = ' ';
2984        }
2985    
2986        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2987     /* move the end-of-line forward */
2988     line->elements[insertHere].indent =
2989        line->elements[insertHere-1].indent;
2990     line->elements[insertHere-1].indent = strdup(indent);
2991        } else {
2992     line->elements[insertHere].indent = strdup(indent);
2993        }
2994    
2995        line->numElements++;
2996    
2997        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2998          line->elements[0].item,
2999          line->elements[insertHere].item,
3000          line->elements[insertHere].indent,
3001          insertHere);
3002    }
3003    
3004    static void removeElement(struct singleLine * line, int removeHere) {
3005        int i;
3006    
3007        /* sanity check */
3008        if (removeHere >= line->numElements) return;
3009    
3010        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
3011          removeHere, line->elements[removeHere].item);
3012    
3013        free(line->elements[removeHere].item);
3014    
3015        if (removeHere > 1) {
3016     /* previous argument gets this argument's post-indentation */
3017     free(line->elements[removeHere-1].indent);
3018     line->elements[removeHere-1].indent =
3019        line->elements[removeHere].indent;
3020        } else {
3021     free(line->elements[removeHere].indent);
3022        }
3023    
3024        /* now collapse the array, but don't bother to realloc smaller */
3025        for (i = removeHere; i < line->numElements - 1; i++)
3026     line->elements[i] = line->elements[i + 1];
3027    
3028        line->numElements--;
3029    }
3030    
3031  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
3032      char * first, * second;      char * first, * second;
3033      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 3050  int updateActualImage(struct grubConfig
3050      struct singleEntry * entry;      struct singleEntry * entry;
3051      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
3052      int index = 0;      int index = 0;
3053      int i, j, k;      int i, k;
3054      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
3055      const char ** arg;      const char ** arg;
3056      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
3057      int firstElement;      int firstElement;
3058      int *usedElements, *usedArgs;      int *usedElements;
3059        int doreplace;
3060    
3061      if (!image) return 0;      if (!image) return 0;
3062    
# Line 1609  int updateActualImage(struct grubConfig Line 3083  int updateActualImage(struct grubConfig
3083   }   }
3084      }      }
3085    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
   
     if (cfg->cfi->keywords[i].key)  
  useKernelArgs = 1;  
3086    
3087      for (i = 0; cfg->cfi->keywords[i].key; i++)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
3088   if (cfg->cfi->keywords[i].type == LT_ROOT) break;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
3089    
3090      if (cfg->cfi->keywords[i].key)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3091   useRoot = 1;         && !multibootArgs);
3092    
3093      k = 0;      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
     for (arg = newArgs; *arg; arg++)  
         k++;  
     usedArgs = calloc(k, sizeof(int));  
   
     while ((entry = findEntryByPath(cfg, image, prefix, &index))) {  
  index++;  
3094    
3095   line = entry->lines;   if (multibootArgs && !entry->multiboot)
3096   while (line && line->type != LT_KERNEL) line = line->next;      continue;
3097   if (!line) continue;  
3098   firstElement = 2;   /* Determine where to put the args.  If this config supports
3099     * LT_KERNELARGS, use that.  Otherwise use
3100          if (entry->multiboot && !multibootArgs) {   * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
3101              /* first mb module line is the real kernel */   */
3102              while (line && line->type != LT_MBMODULE) line = line->next;   if (useKernelArgs) {
3103              firstElement = 2;      line = getLineByType(LT_KERNELARGS, entry->lines);
3104          } else if (useKernelArgs) {      if (!line) {
3105      while (line && line->type != LT_KERNELARGS) line = line->next;   /* no LT_KERNELARGS, need to add it */
3106     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
3107           cfg->secondaryIndent, NULL);
3108        }
3109      firstElement = 1;      firstElement = 1;
3110    
3111     } else if (multibootArgs) {
3112        line = getLineByType(LT_HYPER, entry->lines);
3113        if (!line) {
3114     /* a multiboot entry without LT_HYPER? */
3115     continue;
3116        }
3117        firstElement = 2;
3118    
3119     } else {
3120        line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3121        if (!line) {
3122     /* no LT_KERNEL or LT_MBMODULE in this entry? */
3123     continue;
3124        }
3125        firstElement = 2;
3126   }   }
3127    
3128   if (!line && useKernelArgs) {   /* handle the elilo case which does:
3129      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
3130      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
3131     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
3132        /* this is a multiboot entry, make sure there's
3133         * -- on the args line
3134         */
3135        for (i = firstElement; i < line->numElements; i++) {
3136     if (!strcmp(line->elements[i].item, "--"))
3137        break;
3138        }
3139        if (i == line->numElements) {
3140     /* assume all existing args are kernel args,
3141     * prepend -- to make it official
3142     */
3143     insertElement(line, "--", firstElement, cfg->cfi);
3144     i = firstElement;
3145        }
3146        if (!multibootArgs) {
3147     /* kernel args start after the -- */
3148     firstElement = i + 1;
3149        }
3150     } else if (cfg->cfi->mbConcatArgs) {
3151        /* this is a non-multiboot entry, remove hyper args */
3152        for (i = firstElement; i < line->numElements; i++) {
3153     if (!strcmp(line->elements[i].item, "--"))
3154        break;
3155        }
3156        if (i < line->numElements) {
3157     /* remove args up to -- */
3158     while (strcmp(line->elements[firstElement].item, "--"))
3159        removeElement(line, firstElement);
3160     /* remove -- */
3161     removeElement(line, firstElement);
3162        }
3163   }   }
3164    
3165          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
3166    
3167          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
3168   for (arg = newArgs; *arg; arg++) {  
3169              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
3170      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
3171     if (multibootArgs && cfg->cfi->mbConcatArgs &&
3172        !strcmp(line->elements[i].item, "--"))
3173     {
3174        /* reached the end of hyper args, insert here */
3175        doreplace = 0;
3176        break;  
3177     }
3178                  if (usedElements[i])                  if (usedElements[i])
3179                      continue;                      continue;
3180   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3181                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3182      break;      break;
3183                  }                  }
3184              }              }
     chptr = strchr(*arg, '=');  
3185    
3186      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
3187   /* replace */   /* direct replacement */
3188   free(line->elements[i].item);   free(line->elements[i].item);
3189   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("");  
  }  
3190    
3191   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
3192   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
3193      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
3194   /* append */   if (rootLine) {
3195   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
3196   (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(" ");  
3197   } else {   } else {
3198      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
3199         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
3200   }   }
3201        }
3202    
3203   line->numElements++;      else {
3204     /* insert/append */
3205     insertElement(line, *arg, i, cfg->cfi);
3206     usedElements = realloc(usedElements, line->numElements *
3207           sizeof(*usedElements));
3208     memmove(&usedElements[i + 1], &usedElements[i],
3209     line->numElements - i - 1);
3210     usedElements[i] = 1;
3211    
3212   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
3213     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
3214     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
3215   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
3216      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
3217      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
3218   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
3219   }   }
3220      }      }
             k++;  
3221   }   }
3222    
3223          free(usedElements);          free(usedElements);
3224    
  /* 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? */  
3225   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
3226      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3227   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3228        !strcmp(line->elements[i].item, "--"))
3229        /* reached the end of hyper args, stop here */
3230        break;
3231     if (!argMatch(line->elements[i].item, *arg)) {
3232        removeElement(line, i);
3233      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;  
3234   }   }
3235        }
3236   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3237        if (useRoot && !strncmp(*arg, "root=", 5)) {
3238   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3239      line->elements[j - 1] = line->elements[j];   if (rootLine)
3240        removeLine(entry, rootLine);
  line->numElements--;  
3241      }      }
3242   }   }
3243    
# Line 1760  int updateActualImage(struct grubConfig Line 3248  int updateActualImage(struct grubConfig
3248   }   }
3249      }      }
3250    
     free(usedArgs);  
3251      free(newArgs);      free(newArgs);
3252      free(oldArgs);      free(oldArgs);
3253    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3273  int updateImage(struct grubConfig * cfg,
3273      return rc;      return rc;
3274  }  }
3275    
3276    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3277     const char * image, const char * prefix, const char * initrd) {
3278        struct singleEntry * entry;
3279        struct singleLine * line, * kernelLine, *endLine = NULL;
3280        int index = 0;
3281    
3282        if (!image) return 0;
3283    
3284        for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) {
3285            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3286            if (!kernelLine) continue;
3287    
3288            if (prefix) {
3289                int prefixLen = strlen(prefix);
3290                if (!strncmp(initrd, prefix, prefixLen))
3291                    initrd += prefixLen;
3292            }
3293     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3294     if (endLine)
3295        removeLine(entry, endLine);
3296            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3297     kernelLine->indent, initrd);
3298            if (!line)
3299        return 1;
3300     if (endLine) {
3301        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3302                if (!line)
3303     return 1;
3304     }
3305    
3306            break;
3307        }
3308    
3309        return 0;
3310    }
3311    
3312    int updateInitrd(struct grubConfig * cfg, const char * image,
3313                     const char * prefix, const char * initrd) {
3314        struct singleEntry * entry;
3315        struct singleLine * line, * kernelLine, *endLine = NULL;
3316        int index = 0;
3317    
3318        if (!image) return 0;
3319    
3320        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3321            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3322            if (!kernelLine) continue;
3323    
3324            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3325            if (line)
3326                removeLine(entry, line);
3327            if (prefix) {
3328                int prefixLen = strlen(prefix);
3329                if (!strncmp(initrd, prefix, prefixLen))
3330                    initrd += prefixLen;
3331            }
3332     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3333     if (endLine)
3334        removeLine(entry, endLine);
3335     enum lineType_e lt;
3336     switch(kernelLine->type) {
3337        case LT_KERNEL:
3338            lt = LT_INITRD;
3339     break;
3340        case LT_KERNEL_EFI:
3341            lt = LT_INITRD_EFI;
3342     break;
3343        case LT_KERNEL_16:
3344            lt = LT_INITRD_16;
3345     break;
3346        default:
3347            lt = preferredLineType(LT_INITRD, cfg->cfi);
3348     }
3349            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3350            if (!line)
3351        return 1;
3352     if (endLine) {
3353        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3354                if (!line)
3355     return 1;
3356     }
3357    
3358            break;
3359        }
3360    
3361        return 0;
3362    }
3363    
3364  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3365      int fd;      int fd;
3366      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3384  int checkDeviceBootloader(const char * d
3384      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3385   return 0;   return 0;
3386    
3387      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3388   offset = boot[2] + 2;   offset = boot[2] + 2;
3389      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3390   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3391      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3392   offset = boot[1] + 2;        offset = boot[1] + 2;
3393            /*
3394     * it looks like grub, when copying stage1 into the mbr, patches stage1
3395     * right after the JMP location, replacing other instructions such as
3396     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3397     * different bytes.
3398     */
3399          if ((bootSect[offset + 1] == NOOP_OPCODE)
3400      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3401     offset = offset + 3;
3402          }
3403      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3404   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3405      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3541  int checkForLilo(struct grubConfig * con
3541      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3542  }  }
3543    
3544    int checkForGrub2(struct grubConfig * config) {
3545        if (!access("/etc/grub.d/", R_OK))
3546     return 2;
3547    
3548        return 1;
3549    }
3550    
3551  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3552      int fd;      int fd;
3553      unsigned char bootSect[512];      unsigned char bootSect[512];
3554      char * boot;      char * boot;
3555        int onSuse = isSuseSystem();
3556    
3557      if (parseSysconfigGrub(NULL, &boot))  
3558   return 0;      if (onSuse) {
3559     if (parseSuseGrubConf(NULL, &boot))
3560        return 0;
3561        } else {
3562     if (parseSysconfigGrub(NULL, &boot))
3563        return 0;
3564        }
3565    
3566      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3567      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3575  int checkForGrub(struct grubConfig * con
3575      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3576   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3577   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3578     close(fd);
3579     return 1;
3580        }
3581        close(fd);
3582    
3583        /* The more elaborate checks do not work on SuSE. The checks done
3584         * seem to be reasonble (at least for now), so just return success
3585         */
3586        if (onSuse)
3587     return 2;
3588    
3589        return checkDeviceBootloader(boot, bootSect);
3590    }
3591    
3592    int checkForExtLinux(struct grubConfig * config) {
3593        int fd;
3594        unsigned char bootSect[512];
3595        char * boot;
3596        char executable[] = "/boot/extlinux/extlinux";
3597    
3598        printf("entered: checkForExtLinux()\n");
3599    
3600        if (parseSysconfigGrub(NULL, &boot))
3601     return 0;
3602    
3603        /* assume grub is not installed -- not an error condition */
3604        if (!boot)
3605     return 0;
3606    
3607        fd = open(executable, O_RDONLY);
3608        if (fd < 0)
3609     /* this doesn't exist if grub hasn't been installed */
3610     return 0;
3611    
3612        if (read(fd, bootSect, 512) != 512) {
3613     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3614     executable, strerror(errno));
3615   return 1;   return 1;
3616      }      }
3617      close(fd);      close(fd);
# Line 1983  int checkForGrub(struct grubConfig * con Line 3619  int checkForGrub(struct grubConfig * con
3619      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3620  }  }
3621    
3622    int checkForYaboot(struct grubConfig * config) {
3623        /*
3624         * This is a simplistic check that we consider good enough for own puporses
3625         *
3626         * If we were to properly check if yaboot is *installed* we'd need to:
3627         * 1) get the system boot device (LT_BOOT)
3628         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3629         *    the content on the boot device
3630         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3631         * 4) check again if binary and boot device contents match
3632         */
3633        if (!access("/etc/yaboot.conf", R_OK))
3634     return 2;
3635    
3636        return 1;
3637    }
3638    
3639    int checkForElilo(struct grubConfig * config) {
3640        if (!access("/etc/elilo.conf", R_OK))
3641     return 2;
3642    
3643        return 1;
3644    }
3645    
3646  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3647      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3648    
# Line 1994  static char * getRootSpecifier(char * st Line 3654  static char * getRootSpecifier(char * st
3654      return rootspec;      return rootspec;
3655  }  }
3656    
3657    static char * getInitrdVal(struct grubConfig * config,
3658       const char * prefix, struct singleLine *tmplLine,
3659       const char * newKernelInitrd,
3660       const char ** extraInitrds, int extraInitrdCount)
3661    {
3662        char *initrdVal, *end;
3663        int i;
3664        size_t totalSize;
3665        size_t prefixLen;
3666        char separatorChar;
3667    
3668        prefixLen = strlen(prefix);
3669        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3670    
3671        for (i = 0; i < extraInitrdCount; i++) {
3672     totalSize += sizeof(separatorChar);
3673     totalSize += strlen(extraInitrds[i]) - prefixLen;
3674        }
3675    
3676        initrdVal = end = malloc(totalSize);
3677    
3678        end = stpcpy (end, newKernelInitrd + prefixLen);
3679    
3680        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3681        for (i = 0; i < extraInitrdCount; i++) {
3682     const char *extraInitrd;
3683     int j;
3684    
3685     extraInitrd = extraInitrds[i] + prefixLen;
3686     /* Don't add entries that are already there */
3687     if (tmplLine != NULL) {
3688        for (j = 2; j < tmplLine->numElements; j++)
3689     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3690        break;
3691    
3692        if (j != tmplLine->numElements)
3693     continue;
3694     }
3695    
3696     *end++ = separatorChar;
3697     end = stpcpy(end, extraInitrd);
3698        }
3699    
3700        return initrdVal;
3701    }
3702    
3703  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3704           const char * prefix,           const char * prefix,
3705   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3706   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3707                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3708                     const char * newMBKernel, const char * newMBKernelArgs) {
3709      struct singleEntry * new;      struct singleEntry * new;
3710      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3711      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3712      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3713    
3714      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3715    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3739  int addNewKernel(struct grubConfig * con
3739      config->entries = new;      config->entries = new;
3740    
3741      /* copy/update from the template */      /* copy/update from the template */
3742      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3743        if (newKernelInitrd)
3744     needs |= NEED_INITRD;
3745      if (newMBKernel) {      if (newMBKernel) {
3746          needs |= KERNEL_MB;          needs |= NEED_MB;
3747          new->multiboot = 1;          new->multiboot = 1;
3748      }      }
3749    
3750      if (template) {      if (template) {
3751   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3752      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3753      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3754   indent = tmplLine->indent;   {
3755        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3756    
3757      /* skip comments */      /* skip comments */
3758      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3759      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3760      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3761    
3762      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3763      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3764        /* it's not a multiboot template and this is the kernel
3765              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3766                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3767                  struct singleLine *l;       */
3768                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3769     /* insert the hypervisor first */
3770                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3771                                    config->secondaryIndent,    tmplLine->indent,
3772                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3773                     /* set up for adding the kernel line */
3774                  tmplLine = lastLine;   free(tmplLine->indent);
3775                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3776                      new->lines = l;   needs &= ~NEED_MB;
3777                  } else {      }
3778                      newLine->next = l;      if (needs & NEED_KERNEL) {
3779                      newLine = l;   /* use addLineTmpl to preserve line elements,
3780                  }   * otherwise we could just call addLine.  Unfortunately
3781                  continue;   * this means making some changes to the template
3782              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3783                         template->multiboot && !new->multiboot) {   * change below.
3784                  continue; /* don't need multiboot kernel here */   */
3785              }   struct keywordTypes * mbm_kw =
3786        getKeywordByType(LT_MBMODULE, config->cfi);
3787      if (!new->lines) {   if (mbm_kw) {
3788   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3789   new->lines = newLine;      free(tmplLine->elements[0].item);
3790      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3791   newLine->next = malloc(sizeof(*newLine));   }
3792   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3793      }        newKernelPath + strlen(prefix), config->cfi);
3794     needs &= ~NEED_KERNEL;
3795        }
3796        if (needs & NEED_MB) { /* !mbHyperFirst */
3797     newLine = addLine(new, config->cfi, LT_HYPER,
3798      config->secondaryIndent,
3799      newMBKernel + strlen(prefix));
3800     needs &= ~NEED_MB;
3801        }
3802     } else if (needs & NEED_KERNEL) {
3803        newLine = addLineTmpl(new, tmplLine, newLine,
3804      newKernelPath + strlen(prefix), config->cfi);
3805        needs &= ~NEED_KERNEL;
3806     }
3807    
3808        } else if (tmplLine->type == LT_HYPER &&
3809           tmplLine->numElements >= 2) {
3810     if (needs & NEED_MB) {
3811        newLine = addLineTmpl(new, tmplLine, newLine,
3812      newMBKernel + strlen(prefix), config->cfi);
3813        needs &= ~NEED_MB;
3814     }
3815    
3816      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3817      newLine->next = NULL;         tmplLine->numElements >= 2) {
3818      newLine->type = tmplLine->type;   if (new->multiboot) {
3819      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3820      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3821      newLine->numElements);        newKernelPath +
3822      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3823   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3824   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3825   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3826      }   char *initrdVal;
3827     initrdVal = getInitrdVal(config, prefix, tmplLine,
3828              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3829      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3830                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3831                  if (!template->multiboot) {        initrdVal, config->cfi);
3832                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3833                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3834                  } else {      }
3835                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3836                      repl = newMBKernel;      /* template is multi but new is not,
3837                  }       * insert the kernel in the first module slot
3838                  if (new->multiboot && !template->multiboot) {       */
3839                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3840                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3841                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3842                  }   strdup(getKeywordByType(tmplLine->type,
3843   free(newLine->elements[1].item);   config->cfi)->key);
3844                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3845                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3846                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3847                                                             rootspec,      needs &= ~NEED_KERNEL;
3848                                                             repl +   } else if (needs & NEED_INITRD) {
3849                                                             strlen(prefix));      char *initrdVal;
3850                  } else {      /* template is multi but new is not,
3851                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3852                                                         strlen(prefix));       */
3853                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3854              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3855                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3856                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3857                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3858                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3859                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3860                      newLine->type = LT_KERNEL;      free(initrdVal);
3861                  }      needs &= ~NEED_INITRD;
3862   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;  
3863    
3864   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3865      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3866      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3867        config->cfi->mbInitRdIsModule) {
3868        /* make sure we don't insert the module initrd
3869         * before the module kernel... if we don't do it here,
3870         * it will be inserted following the template.
3871         */
3872        if (!needs & NEED_KERNEL) {
3873     char *initrdVal;
3874    
3875     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3876     newLine = addLine(new, config->cfi, LT_MBMODULE,
3877      config->secondaryIndent,
3878      initrdVal);
3879     free(initrdVal);
3880     needs &= ~NEED_INITRD;
3881        }
3882     } else if (needs & NEED_INITRD) {
3883        char *initrdVal;
3884        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3885        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3886        free(initrdVal);
3887        needs &= ~NEED_INITRD;
3888   }   }
3889    
3890   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3891   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3892   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3893     char *nkt = malloc(strlen(newKernelTitle)+3);
3894     strcpy(nkt, "'");
3895     strcat(nkt, newKernelTitle);
3896     strcat(nkt, "'");
3897     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3898     free(nkt);
3899     needs &= ~NEED_TITLE;
3900      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3901                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3902                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3903                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3904                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3905                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3906                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3907                                             newLine->numElements);     config->cfi->titleBracketed) {
3908        /* addLineTmpl doesn't handle titleBracketed */
3909                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3910                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3911                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3912                  newLine->numElements = 1;   }
3913              }      } else if (tmplLine->type == LT_ECHO) {
3914        requote(tmplLine, config->cfi);
3915        static const char *prefix = "'Loading ";
3916        if (tmplLine->numElements > 1 &&
3917        strstr(tmplLine->elements[1].item, prefix) &&
3918        masterLine->next &&
3919        iskernel(masterLine->next->type)) {
3920     char *newTitle = malloc(strlen(prefix) +
3921     strlen(newKernelTitle) + 2);
3922    
3923     strcpy(newTitle, prefix);
3924     strcat(newTitle, newKernelTitle);
3925     strcat(newTitle, "'");
3926     newLine = addLine(new, config->cfi, LT_ECHO,
3927     tmplLine->indent, newTitle);
3928     free(newTitle);
3929        } else {
3930     /* pass through other lines from the template */
3931     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3932     config->cfi);
3933        }
3934        } else {
3935     /* pass through other lines from the template */
3936     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3937        }
3938   }   }
3939    
3940      } else {      } else {
3941   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3942      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3943     */
3944     switch (config->cfi->entryStart) {
3945        case LT_KERNEL:
3946        case LT_KERNEL_EFI:
3947        case LT_KERNEL_16:
3948     if (new->multiboot && config->cfi->mbHyperFirst) {
3949        /* fall through to LT_HYPER */
3950     } else {
3951        newLine = addLine(new, config->cfi,
3952              preferredLineType(LT_KERNEL, config->cfi),
3953          config->primaryIndent,
3954          newKernelPath + strlen(prefix));
3955        needs &= ~NEED_KERNEL;
3956        break;
3957     }
3958    
3959        case LT_HYPER:
3960     newLine = addLine(new, config->cfi, LT_HYPER,
3961      config->primaryIndent,
3962      newMBKernel + strlen(prefix));
3963     needs &= ~NEED_MB;
3964   break;   break;
         }  
3965    
3966   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3967      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3968       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3969       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3970      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3971       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3972      default:        config->primaryIndent, nkt);
3973                  /* zipl strikes again */   free(nkt);
3974                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3975                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3976                      chptr = newKernelTitle;   break;
3977                      type = LT_TITLE;      }
3978                      break;      case LT_TITLE:
3979                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3980                      abort();   char * templabel;
3981                  }   int x = 0, y = 0;
3982   }  
3983     templabel = strdup(newKernelTitle);
3984     while( templabel[x]){
3985     if( templabel[x] == ' ' ){
3986     y = x;
3987     while( templabel[y] ){
3988     templabel[y] = templabel[y+1];
3989     y++;
3990     }
3991     }
3992     x++;
3993     }
3994     newLine = addLine(new, config->cfi, LT_TITLE,
3995      config->primaryIndent, templabel);
3996     free(templabel);
3997     }else{
3998     newLine = addLine(new, config->cfi, LT_TITLE,
3999      config->primaryIndent, newKernelTitle);
4000     }
4001     needs &= ~NEED_TITLE;
4002     break;
4003    
4004   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
4005   new->lines = newLine;   abort();
4006     }
4007      }      }
4008    
4009      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
4010          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
4011              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
4012                                config->secondaryIndent,       */
4013                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
4014          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
4015              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
4016                                config->secondaryIndent,    newKernelTitle);
4017                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
4018          /* don't need to check for title as it's guaranteed to have been      }
4019           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
4020           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
4021          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
4022              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
4023                                config->secondaryIndent,   needs &= ~NEED_MB;
4024                                newKernelInitrd + strlen(prefix));      }
4025      } else {      if (needs & NEED_KERNEL) {
4026          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
4027              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4028                                config->secondaryIndent,        config->cfi))
4029                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
4030          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
4031              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
4032                                config->secondaryIndent,    newKernelPath + strlen(prefix));
4033                                newKernelTitle);   needs &= ~NEED_KERNEL;
4034          if (needs & KERNEL_INITRD && newKernelInitrd)      }
4035              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
4036                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
4037                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
4038      newMBKernel + strlen(prefix));
4039     needs &= ~NEED_MB;
4040        }
4041        if (needs & NEED_INITRD) {
4042     char *initrdVal;
4043     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4044     newLine = addLine(new, config->cfi,
4045      (new->multiboot && getKeywordByType(LT_MBMODULE,
4046          config->cfi))
4047       ? LT_MBMODULE
4048       : preferredLineType(LT_INITRD, config->cfi),
4049      config->secondaryIndent,
4050      initrdVal);
4051     free(initrdVal);
4052     needs &= ~NEED_INITRD;
4053        }
4054        if (needs & NEED_END) {
4055     newLine = addLine(new, config->cfi, LT_ENTRY_END,
4056     config->secondaryIndent, NULL);
4057     needs &= ~NEED_END;
4058        }
4059    
4060        if (needs) {
4061     printf(_("grubby: needs=%d, aborting\n"), needs);
4062     abort();
4063      }      }
4064    
4065      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 4068  int addNewKernel(struct grubConfig * con
4068      return 0;      return 0;
4069  }  }
4070    
4071    static void traceback(int signum)
4072    {
4073        void *array[40];
4074        size_t size;
4075    
4076        signal(SIGSEGV, SIG_DFL);
4077        memset(array, '\0', sizeof (array));
4078        size = backtrace(array, 40);
4079    
4080        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4081                (unsigned long)size);
4082        backtrace_symbols_fd(array, size, STDERR_FILENO);
4083        exit(1);
4084    }
4085    
4086  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4087      poptContext optCon;      poptContext optCon;
4088      char * grubConfig = NULL;      const char * grubConfig = NULL;
4089      char * outputFile = NULL;      char * outputFile = NULL;
4090      int arg = 0;      int arg = 0;
4091      int flags = 0;      int flags = 0;
4092      int badImageOkay = 0;      int badImageOkay = 0;
4093        int configureGrub2 = 0;
4094      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4095      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4096        int configureExtLinux = 0;
4097      int bootloaderProbe = 0;      int bootloaderProbe = 0;
4098        int extraInitrdCount = 0;
4099      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
4100      char * newKernelPath = NULL;      char * newKernelPath = NULL;
4101      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 4111  int main(int argc, const char ** argv) {
4111      char * defaultKernel = NULL;      char * defaultKernel = NULL;
4112      char * removeArgs = NULL;      char * removeArgs = NULL;
4113      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4114        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4115        char * envPath = NULL;
4116      const char * chptr = NULL;      const char * chptr = NULL;
4117      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4118      struct grubConfig * config;      struct grubConfig * config;
4119      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4120      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4121      int displayDefault = 0;      int displayDefault = 0;
4122        int displayDefaultIndex = 0;
4123        int displayDefaultTitle = 0;
4124        int defaultIndex = -1;
4125      struct poptOption options[] = {      struct poptOption options[] = {
4126   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4127      _("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 4139  int main(int argc, const char ** argv) {
4139   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4140      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4141      _("bootfs") },      _("bootfs") },
4142  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4143   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4144      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4145  #endif  #endif
4146   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4147      _("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 4152  int main(int argc, const char ** argv) {
4152        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4153        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4154        "template"), NULL },        "template"), NULL },
4155     { "debug", 0, 0, &debug, 0,
4156        _("print debugging information for failures") },
4157   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4158      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4159     { "default-index", 0, 0, &displayDefaultIndex, 0,
4160        _("display the index of the default kernel") },
4161     { "default-title", 0, 0, &displayDefaultTitle, 0,
4162        _("display the title of the default kernel") },
4163   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4164      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4165     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4166        _("force grub2 stanzas to use efi") },
4167     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4168        _("path for environment data"),
4169        _("path") },
4170     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4171        _("configure extlinux bootloader (from syslinux)") },
4172   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4173      _("configure grub bootloader") },      _("configure grub bootloader") },
4174     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4175        _("configure grub2 bootloader") },
4176   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4177      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4178      _("kernel-path") },      _("kernel-path") },
4179   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4180      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4181     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4182        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4183   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4184      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4185   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4199  int main(int argc, const char ** argv) {
4199   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4200      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4201        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4202     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4203        _("make the given entry index the default entry"),
4204        _("entry-index") },
4205   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4206      _("configure silo bootloader") },      _("configure silo bootloader") },
4207   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4219  int main(int argc, const char ** argv) {
4219   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4220      };      };
4221    
4222        useextlinuxmenu=0;
4223    
4224        signal(SIGSEGV, traceback);
4225    
4226        int i = 0;
4227        for (int j = 1; j < argc; j++)
4228     i += strlen(argv[j]) + 1;
4229        saved_command_line = malloc(i);
4230        if (!saved_command_line) {
4231     fprintf(stderr, "grubby: %m\n");
4232     exit(1);
4233        }
4234        saved_command_line[0] = '\0';
4235        for (int j = 1; j < argc; j++) {
4236     strcat(saved_command_line, argv[j]);
4237     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4238        }
4239    
4240      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4241      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4242    
# Line 2391  int main(int argc, const char ** argv) { Line 4246  int main(int argc, const char ** argv) {
4246      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4247      exit(0);      exit(0);
4248      break;      break;
4249      case 'i':
4250        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4251         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4252        } else {
4253     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4254     return 1;
4255        }
4256        break;
4257   }   }
4258      }      }
4259    
# Line 2406  int main(int argc, const char ** argv) { Line 4269  int main(int argc, const char ** argv) {
4269   return 1;   return 1;
4270      }      }
4271    
4272      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4273   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4274     configureExtLinux ) > 1) {
4275   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4276   return 1;   return 1;
4277      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4278   fprintf(stderr,   fprintf(stderr,
4279      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4280   return 1;   return 1;
4281        } else if (configureGrub2) {
4282     cfi = &grub2ConfigType;
4283     if (envPath)
4284        cfi->envFile = envPath;
4285      } else if (configureLilo) {      } else if (configureLilo) {
4286   cfi = &liloConfigType;   cfi = &liloConfigType;
4287      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4294  int main(int argc, const char ** argv) {
4294          cfi = &siloConfigType;          cfi = &siloConfigType;
4295      } else if (configureZipl) {      } else if (configureZipl) {
4296          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4297        } else if (configureExtLinux) {
4298     cfi = &extlinuxConfigType;
4299     useextlinuxmenu=1;
4300      }      }
4301    
4302      if (!cfi) {      if (!cfi) {
4303            if (grub2FindConfig(&grub2ConfigType))
4304        cfi = &grub2ConfigType;
4305     else
4306        #ifdef __ia64__        #ifdef __ia64__
4307   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4308        #elif __powerpc__        #elif __powerpc__
4309   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4310        #elif __sparc__        #elif __sparc__
4311          cfi = &siloConfigType;              cfi = &siloConfigType;
4312        #elif __s390__        #elif __s390__
4313          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4314        #elif __s390x__        #elif __s390x__
4315          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4316        #else        #else
4317   cfi = &grubConfigType;      cfi = &grubConfigType;
4318        #endif        #endif
4319      }      }
4320    
4321      if (!grubConfig)      if (!grubConfig) {
4322   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4323        grubConfig = cfi->findConfig(cfi);
4324     if (!grubConfig)
4325        grubConfig = cfi->defaultConfig;
4326        }
4327    
4328      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4329    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4330    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4331        (defaultIndex >= 0))) {
4332   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4333    "specified option"));    "specified option"));
4334   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4344  int main(int argc, const char ** argv) {
4344      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4345   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4346   return 1;   return 1;
4347      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4348    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4349    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4350   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4351   return 1;   return 1;
4352      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4370  int main(int argc, const char ** argv) {
4370   makeDefault = 1;   makeDefault = 1;
4371   defaultKernel = NULL;   defaultKernel = NULL;
4372      }      }
4373        else if (defaultKernel && (defaultIndex >= 0)) {
4374     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4375      "may not be used together\n"));
4376     return 1;
4377        }
4378    
4379      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4380   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4381   "is used\n"));   "is used\n"));
4382   return 1;   return 1;
4383      }      }
4384    
4385      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4386   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4387          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4388     && (defaultIndex == -1)) {
4389   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4390   return 1;   return 1;
4391      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4405  int main(int argc, const char ** argv) {
4405   bootPrefix = "";   bootPrefix = "";
4406      }      }
4407    
4408        if (!cfi->mbAllowExtraInitRds &&
4409     extraInitrdCount > 0) {
4410     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4411     return 1;
4412        }
4413    
4414      if (bootloaderProbe) {      if (bootloaderProbe) {
4415   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4416   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4417    
4418     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4419     if (grub2config) {
4420        gconfig = readConfig(grub2config, &grub2ConfigType);
4421        if (!gconfig)
4422     gr2c = 1;
4423        else
4424     gr2c = checkForGrub2(gconfig);
4425     }
4426    
4427   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4428      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4429        gconfig = readConfig(grubconfig, &grubConfigType);
4430      if (!gconfig)      if (!gconfig)
4431   grc = 1;   grc = 1;
4432      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4441  int main(int argc, const char ** argv) {
4441   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4442   }   }
4443    
4444   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4445        econfig = readConfig(eliloConfigType.defaultConfig,
4446     &eliloConfigType);
4447        if (!econfig)
4448     erc = 1;
4449        else
4450     erc = checkForElilo(econfig);
4451     }
4452    
4453     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4454        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4455        if (!lconfig)
4456     extrc = 1;
4457        else
4458     extrc = checkForExtLinux(lconfig);
4459     }
4460    
4461    
4462     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4463        yconfig = readConfig(yabootConfigType.defaultConfig,
4464     &yabootConfigType);
4465        if (!yconfig)
4466     yrc = 1;
4467        else
4468     yrc = checkForYaboot(yconfig);
4469     }
4470    
4471     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4472     erc == 1)
4473        return 1;
4474    
4475   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4476     if (gr2c == 2) printf("grub2\n");
4477   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4478     if (extrc == 2) printf("extlinux\n");
4479     if (yrc == 2) printf("yaboot\n");
4480     if (erc == 2) printf("elilo\n");
4481    
4482   return 0;   return 0;
4483      }      }
4484    
4485        if (grubConfig == NULL) {
4486     printf("Could not find bootloader configuration file.\n");
4487     exit(1);
4488        }
4489    
4490      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4491      if (!config) return 1;      if (!config) return 1;
4492    
# Line 2557  int main(int argc, const char ** argv) { Line 4496  int main(int argc, const char ** argv) {
4496          char * rootspec;          char * rootspec;
4497    
4498   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4499     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4500     cfi->defaultIsSaved)
4501        config->defaultImage = 0;
4502   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4503   if (!entry) return 0;   if (!entry) return 0;
4504   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4505    
4506   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4507   if (!line) return 0;   if (!line) return 0;
4508    
4509          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4511  int main(int argc, const char ** argv) {
4511                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4512    
4513   return 0;   return 0;
4514    
4515        } else if (displayDefaultTitle) {
4516     struct singleLine * line;
4517     struct singleEntry * entry;
4518    
4519     if (config->defaultImage == -1) return 0;
4520     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4521     cfi->defaultIsSaved)
4522        config->defaultImage = 0;
4523     entry = findEntryByIndex(config, config->defaultImage);
4524     if (!entry) return 0;
4525    
4526     if (!configureGrub2) {
4527      line = getLineByType(LT_TITLE, entry->lines);
4528      if (!line) return 0;
4529      printf("%s\n", line->elements[1].item);
4530    
4531     } else {
4532      char * title;
4533    
4534      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4535      line = getLineByType(LT_MENUENTRY, entry->lines);
4536      if (!line) return 0;
4537      title = grub2ExtractTitle(line);
4538      if (title)
4539        printf("%s\n", title);
4540     }
4541     return 0;
4542    
4543        } else if (displayDefaultIndex) {
4544            if (config->defaultImage == -1) return 0;
4545     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4546     cfi->defaultIsSaved)
4547        config->defaultImage = 0;
4548            printf("%i\n", config->defaultImage);
4549            return 0;
4550    
4551      } else if (kernelInfo)      } else if (kernelInfo)
4552   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4553    
# Line 2581  int main(int argc, const char ** argv) { Line 4559  int main(int argc, const char ** argv) {
4559      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4560      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4561      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4562      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4563      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4564      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4565                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4566        if (updateKernelPath && newKernelInitrd) {
4567        if (newMBKernel) {
4568        if (addMBInitrd(config, newMBKernel, updateKernelPath,
4569     bootPrefix, newKernelInitrd))
4570        return 1;
4571        } else {
4572        if (updateInitrd(config, updateKernelPath, bootPrefix,
4573     newKernelInitrd))
4574     return 1;
4575        }
4576        }
4577      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4578                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4579                         (const char **)extraInitrds, extraInitrdCount,
4580                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4581            
4582    
# Line 2597  int main(int argc, const char ** argv) { Line 4587  int main(int argc, const char ** argv) {
4587      }      }
4588    
4589      if (!outputFile)      if (!outputFile)
4590   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4591    
4592      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4593  }  }

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