Magellan Linux

Diff of /tags/grubby-8_38/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 2972 by niro, Thu Jun 30 10:17:00 2016 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    #if defined(__aarch64__)
64    #define isEfiOnly 1
65    #else
66    #define isEfiOnly 0
67    #endif
68    
69    char *saved_command_line = NULL;
70    
71  /* comments get lumped in with indention */  /* comments get lumped in with indention */
72  struct lineElement {  struct lineElement {
73      char * item;      char * item;
74      char * indent;      char * indent;
75  };  };
76    
77  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
78         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
79         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
80        LT_KERNEL       = 1 << 2,
81        LT_INITRD       = 1 << 3,
82        LT_HYPER        = 1 << 4,
83        LT_DEFAULT      = 1 << 5,
84        LT_MBMODULE     = 1 << 6,
85        LT_ROOT         = 1 << 7,
86        LT_FALLBACK     = 1 << 8,
87        LT_KERNELARGS   = 1 << 9,
88        LT_BOOT         = 1 << 10,
89        LT_BOOTROOT     = 1 << 11,
90        LT_LBA          = 1 << 12,
91        LT_OTHER        = 1 << 13,
92        LT_GENERIC      = 1 << 14,
93        LT_ECHO    = 1 << 16,
94        LT_MENUENTRY    = 1 << 17,
95        LT_ENTRY_END    = 1 << 18,
96        LT_SET_VARIABLE = 1 << 19,
97        LT_KERNEL_EFI   = 1 << 20,
98        LT_INITRD_EFI   = 1 << 21,
99        LT_KERNEL_16    = 1 << 22,
100        LT_INITRD_16    = 1 << 23,
101        LT_DEVTREE      = 1 << 24,
102        LT_UNKNOWN      = 1 << 25,
103    };
104    
105  struct singleLine {  struct singleLine {
106      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 121  struct singleEntry {
121    
122  #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 */
123    
124  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
125  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
126  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
127  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
128  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
129    #define NEED_MB      (1 << 4)
130    #define NEED_END     (1 << 5)
131    #define NEED_DEVTREE (1 << 6)
132    
133  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
134  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
135    #define DEFAULT_SAVED_GRUB2 -3
136    
137  struct keywordTypes {  struct keywordTypes {
138      char * key;      char * key;
139      enum lineType_e type;      enum lineType_e type;
140      char nextChar;      char nextChar;
141  } ;      char separatorChar;
142    };
143    
144    struct configFileInfo;
145    
146    typedef const char *(*findConfigFunc)(struct configFileInfo *);
147    typedef const int (*writeLineFunc)(struct configFileInfo *,
148     struct singleLine *line);
149    typedef char *(*getEnvFunc)(struct configFileInfo *, char *name);
150    typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value);
151    
152  struct configFileInfo {  struct configFileInfo {
153      char * defaultConfig;      char * defaultConfig;
154        findConfigFunc findConfig;
155        writeLineFunc writeLine;
156        getEnvFunc getEnv;
157        setEnvFunc setEnv;
158      struct keywordTypes * keywords;      struct keywordTypes * keywords;
159        int caseInsensitive;
160      int defaultIsIndex;      int defaultIsIndex;
161        int defaultIsVariable;
162      int defaultSupportSaved;      int defaultSupportSaved;
163      enum lineType_e entrySeparator;      int defaultIsSaved;
164        int defaultIsUnquoted;
165        enum lineType_e entryStart;
166        enum lineType_e entryEnd;
167      int needsBootPrefix;      int needsBootPrefix;
168      int argsInQuotes;      int argsInQuotes;
169      int maxTitleLength;      int maxTitleLength;
170      int titleBracketed;      int titleBracketed;
171        int titlePosition;
172        int mbHyperFirst;
173        int mbInitRdIsModule;
174        int mbConcatArgs;
175        int mbAllowExtraInitRds;
176        char *envFile;
177  };  };
178    
179  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 182  struct keywordTypes grubKeywords[] = {
182      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
183      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
184      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
185      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
186      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
187        { "kernel",     LT_HYPER,       ' ' },
188      { NULL,    0, 0 },      { NULL,    0, 0 },
189  };  };
190    
191    const char *grubFindConfig(struct configFileInfo *cfi) {
192        static const char *configFiles[] = {
193     "/boot/grub/grub.conf",
194     "/boot/grub/menu.lst",
195     "/etc/grub.conf",
196     "/boot/grub2/grub.cfg",
197     "/boot/grub2-efi/grub.cfg",
198     NULL
199        };
200        static int i = -1;
201    
202        if (i == -1) {
203     for (i = 0; configFiles[i] != NULL; i++) {
204        dbgPrintf("Checking \"%s\": ", configFiles[i]);
205        if (!access(configFiles[i], R_OK)) {
206     dbgPrintf("found\n");
207     return configFiles[i];
208        }
209        dbgPrintf("not found\n");
210     }
211        }
212        return configFiles[i];
213    }
214    
215  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
216      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
217      grubKeywords,    /* keywords */      .keywords = grubKeywords,
218      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
219      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
220      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
221      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
222      0,    /* argsInQuotes */      .mbHyperFirst = 1,
223      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
224      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
225    };
226    
227    struct keywordTypes grub2Keywords[] = {
228        { "menuentry",  LT_MENUENTRY,   ' ' },
229        { "}",          LT_ENTRY_END,   ' ' },
230        { "echo",       LT_ECHO,        ' ' },
231        { "set",        LT_SET_VARIABLE,' ', '=' },
232        { "root",       LT_BOOTROOT,    ' ' },
233        { "default",    LT_DEFAULT,     ' ' },
234        { "fallback",   LT_FALLBACK,    ' ' },
235        { "linux",      LT_KERNEL,      ' ' },
236        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
237        { "linux16",    LT_KERNEL_16,   ' ' },
238        { "initrd",     LT_INITRD,      ' ', ' ' },
239        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
240        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
241        { "module",     LT_MBMODULE,    ' ' },
242        { "kernel",     LT_HYPER,       ' ' },
243        { "devicetree", LT_DEVTREE,  ' ' },
244        { NULL, 0, 0 },
245    };
246    
247    const char *grub2FindConfig(struct configFileInfo *cfi) {
248        static const char *configFiles[] = {
249     "/boot/grub/grub-efi.cfg",
250     "/boot/grub/grub.cfg",
251     NULL
252        };
253        static int i = -1;
254        static const char *grub_cfg = "/boot/grub/grub.cfg";
255        int rc = -1;
256    
257        if (i == -1) {
258     for (i = 0; configFiles[i] != NULL; i++) {
259        dbgPrintf("Checking \"%s\": ", configFiles[i]);
260        if ((rc = access(configFiles[i], R_OK))) {
261     if (errno == EACCES) {
262        printf("Unable to access bootloader configuration file "
263           "\"%s\": %m\n", configFiles[i]);
264        exit(1);
265     }
266     continue;
267        } else {
268     dbgPrintf("found\n");
269     return configFiles[i];
270        }
271     }
272        }
273    
274        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
275         * that isn't in grub1, and if it exists, return the config file path
276         * that they use. */
277        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
278     dbgPrintf("found\n");
279     return grub_cfg;
280        }
281    
282        dbgPrintf("not found\n");
283        return configFiles[i];
284    }
285    
286    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
287    static char *grub2GetEnv(struct configFileInfo *info, char *name)
288    {
289        static char buf[1025];
290        char *s = NULL;
291        char *ret = NULL;
292        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
293        int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name);
294    
295        if (rc < 0)
296     return NULL;
297    
298        FILE *f = popen(s, "r");
299        if (!f)
300     goto out;
301    
302        memset(buf, '\0', sizeof (buf));
303        ret = fgets(buf, 1024, f);
304        pclose(f);
305    
306        if (ret) {
307     ret += strlen(name) + 1;
308     ret[strlen(ret) - 1] = '\0';
309        }
310        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
311    out:
312        free(s);
313        return ret;
314    }
315    
316    static int sPopCount(const char *s, const char *c)
317    {
318        int ret = 0;
319        if (!s)
320     return -1;
321        for (int i = 0; s[i] != '\0'; i++)
322     for (int j = 0; c[j] != '\0'; j++)
323        if (s[i] == c[j])
324     ret++;
325        return ret;
326    }
327    
328    static char *shellEscape(const char *s)
329    {
330        int l = strlen(s) + sPopCount(s, "'") * 2;
331    
332        char *ret = calloc(l+1, sizeof (*ret));
333        if (!ret)
334     return NULL;
335        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
336     if (s[i] == '\'')
337        ret[j++] = '\\';
338     ret[j] = s[i];
339        }
340        return ret;
341    }
342    
343    static void unquote(char *s)
344    {
345        int l = strlen(s);
346    
347        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
348     memmove(s, s+1, l-2);
349     s[l-2] = '\0';
350        }
351    }
352    
353    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
354    {
355        char *s = NULL;
356        int rc = 0;
357        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
358    
359        unquote(value);
360        value = shellEscape(value);
361        if (!value)
362        return -1;
363    
364        rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value);
365        free(value);
366        if (rc <0)
367     return -1;
368    
369        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
370        rc = system(s);
371        free(s);
372        return rc;
373    }
374    
375    /* this is a gigantic hack to avoid clobbering grub2 variables... */
376    static int is_special_grub2_variable(const char *name)
377    {
378        if (!strcmp(name,"\"${next_entry}\""))
379     return 1;
380        if (!strcmp(name,"\"${prev_saved_entry}\""))
381     return 1;
382        return 0;
383    }
384    
385    int sizeOfSingleLine(struct singleLine * line) {
386      int count = 0;
387    
388      for (int i = 0; i < line->numElements; i++) {
389        int indentSize = 0;
390    
391        count = count + strlen(line->elements[i].item);
392    
393        indentSize = strlen(line->elements[i].indent);
394        if (indentSize > 0)
395          count = count + indentSize;
396        else
397          /* be extra safe and add room for whitespaces */
398          count = count + 1;
399      }
400    
401      /* room for trailing terminator */
402      count = count + 1;
403    
404      return count;
405    }
406    
407    static int isquote(char q)
408    {
409        if (q == '\'' || q == '\"')
410     return 1;
411        return 0;
412    }
413    
414    static int iskernel(enum lineType_e type) {
415        return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
416    }
417    
418    static int isinitrd(enum lineType_e type) {
419        return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
420    }
421    
422    char *grub2ExtractTitle(struct singleLine * line) {
423        char * current;
424        char * current_indent;
425        int current_len;
426        int current_indent_len;
427        int i;
428    
429        /* bail out if line does not start with menuentry */
430        if (strcmp(line->elements[0].item, "menuentry"))
431          return NULL;
432    
433        i = 1;
434        current = line->elements[i].item;
435        current_len = strlen(current);
436    
437        /* if second word is quoted, strip the quotes and return single word */
438        if (isquote(*current) && isquote(current[current_len - 1])) {
439     char *tmp;
440    
441     tmp = strdup(current);
442     *(tmp + current_len - 1) = '\0';
443     return ++tmp;
444        }
445    
446        /* if no quotes, return second word verbatim */
447        if (!isquote(*current))
448     return current;
449    
450        /* second element start with a quote, so we have to find the element
451         * whose last character is also quote (assuming it's the closing one) */
452        int resultMaxSize;
453        char * result;
454        
455        resultMaxSize = sizeOfSingleLine(line);
456        result = malloc(resultMaxSize);
457        snprintf(result, resultMaxSize, "%s", ++current);
458        
459        i++;
460        for (; i < line->numElements; ++i) {
461     current = line->elements[i].item;
462     current_len = strlen(current);
463     current_indent = line->elements[i].indent;
464     current_indent_len = strlen(current_indent);
465    
466     strncat(result, current_indent, current_indent_len);
467     if (!isquote(current[current_len-1])) {
468        strncat(result, current, current_len);
469     } else {
470        strncat(result, current, current_len - 1);
471        break;
472     }
473        }
474        return result;
475    }
476    
477    struct configFileInfo grub2ConfigType = {
478        .findConfig = grub2FindConfig,
479        .getEnv = grub2GetEnv,
480        .setEnv = grub2SetEnv,
481        .keywords = grub2Keywords,
482        .defaultIsIndex = 1,
483        .defaultSupportSaved = 1,
484        .defaultIsVariable = 1,
485        .entryStart = LT_MENUENTRY,
486        .entryEnd = LT_ENTRY_END,
487        .titlePosition = 1,
488        .needsBootPrefix = 1,
489        .mbHyperFirst = 1,
490        .mbInitRdIsModule = 1,
491        .mbAllowExtraInitRds = 1,
492  };  };
493    
494  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 522  struct keywordTypes yabootKeywords[] = {
522      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
523      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
524      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
525      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
526      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
527      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
528      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 542  struct keywordTypes liloKeywords[] = {
542      { NULL,    0, 0 },      { NULL,    0, 0 },
543  };  };
544    
545    struct keywordTypes eliloKeywords[] = {
546        { "label",    LT_TITLE,    '=' },
547        { "root",    LT_ROOT,    '=' },
548        { "default",    LT_DEFAULT,    '=' },
549        { "image",    LT_KERNEL,    '=' },
550        { "initrd",    LT_INITRD,    '=' },
551        { "append",    LT_KERNELARGS,  '=' },
552        { "vmm",    LT_HYPER,       '=' },
553        { NULL,    0, 0 },
554    };
555    
556  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
557      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
558      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 574  struct keywordTypes ziplKeywords[] = {
574      { NULL,         0, 0 },      { NULL,         0, 0 },
575  };  };
576    
577    struct keywordTypes extlinuxKeywords[] = {
578        { "label",    LT_TITLE,    ' ' },
579        { "root",    LT_ROOT,    ' ' },
580        { "default",    LT_DEFAULT,    ' ' },
581        { "kernel",    LT_KERNEL,    ' ' },
582        { "initrd",    LT_INITRD,      ' ', ',' },
583        { "append",    LT_KERNELARGS,  ' ' },
584        { "prompt",     LT_UNKNOWN,     ' ' },
585        { "fdt",        LT_DEVTREE,     ' ' },
586        { "fdtdir",     LT_DEVTREE,     ' ' },
587        { NULL,    0, 0 },
588    };
589    int useextlinuxmenu;
590  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
591      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
592      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
593      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
594      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
595      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
596      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
597  };  };
598    
599  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
600      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
601      liloKeywords,    /* keywords */      .keywords = liloKeywords,
602      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
603      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
604      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
605  };  };
606    
607  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
608      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
609      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
610      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
611      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
612      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
613      1,    /* needsBootPrefix */      .maxTitleLength = 15,
614      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
615  };  };
616    
617  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
618      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
619      siloKeywords,    /* keywords */      .keywords = siloKeywords,
620      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
621      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
622      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
623      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
624  };  };
625    
626  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
627      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
628      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
629      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
630      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
631      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
632      0,    /* needsBootPrefix */  };
633      1,    /* argsInQuotes */  
634      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
635      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
636        .keywords = extlinuxKeywords,
637        .caseInsensitive = 1,
638        .entryStart = LT_TITLE,
639        .needsBootPrefix = 1,
640        .maxTitleLength = 255,
641        .mbAllowExtraInitRds = 1,
642        .defaultIsUnquoted = 1,
643  };  };
644    
645  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 654  struct grubConfig {
654      struct configFileInfo * cfi;      struct configFileInfo * cfi;
655  };  };
656    
657    blkid_cache blkid;
658    
659  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
660  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
661       const char * path, const char * prefix,       const char * path, const char * prefix,
662       int * index);       int * index);
663  static char * strndup(char * from, int len);  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
664          int * index);
665  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
666  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
667    struct singleLine * lineDup(struct singleLine * line);
668  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
669  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
670       struct configFileInfo * cfi);       struct configFileInfo * cfi);
671  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
672         struct configFileInfo * cfi);         struct configFileInfo * cfi);
673  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
674    static void requote(struct singleLine *line, struct configFileInfo * cfi);
675  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
676      char * to;    const char * item, int insertHere,
677      struct configFileInfo * cfi);
678      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
679      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
680      to[len] = '\0';        struct configFileInfo * cfi);
681    static enum lineType_e getTypeByKeyword(char * keyword,
682      return to;   struct configFileInfo * cfi);
683  }  static struct singleLine * getLineByType(enum lineType_e type,
684     struct singleLine * line);
685    static int checkForExtLinux(struct grubConfig * config);
686    struct singleLine * addLineTmpl(struct singleEntry * entry,
687                                    struct singleLine * tmplLine,
688                                    struct singleLine * prevLine,
689                                    const char * val,
690     struct configFileInfo * cfi);
691    struct singleLine *  addLine(struct singleEntry * entry,
692                                 struct configFileInfo * cfi,
693                                 enum lineType_e type, char * defaultIndent,
694                                 const char * val);
695    
696  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
697  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 726  static char * sdupprintf(const char *for
726      return buf;      return buf;
727  }  }
728    
729    static enum lineType_e preferredLineType(enum lineType_e type,
730     struct configFileInfo *cfi) {
731        if (isEfi && cfi == &grub2ConfigType) {
732     switch (type) {
733     case LT_KERNEL:
734        return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
735     case LT_INITRD:
736        return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
737     default:
738        return type;
739     }
740    #if defined(__i386__) || defined(__x86_64__)
741        } else if (cfi == &grub2ConfigType) {
742     switch (type) {
743     case LT_KERNEL:
744        return LT_KERNEL_16;
745     case LT_INITRD:
746        return LT_INITRD_16;
747     default:
748        return type;
749     }
750    #endif
751        }
752        return type;
753    }
754    
755    static struct keywordTypes * getKeywordByType(enum lineType_e type,
756          struct configFileInfo * cfi) {
757        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
758     if (kw->type == type)
759        return kw;
760        }
761        return NULL;
762    }
763    
764    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
765        struct keywordTypes *kt = getKeywordByType(type, cfi);
766        if (kt)
767     return kt->key;
768        return "unknown";
769    }
770    
771    static char * getpathbyspec(char *device) {
772        if (!blkid)
773            blkid_get_cache(&blkid, NULL);
774    
775        return blkid_get_devname(blkid, device, NULL);
776    }
777    
778    static char * getuuidbydev(char *device) {
779        if (!blkid)
780     blkid_get_cache(&blkid, NULL);
781    
782        return blkid_get_tag_value(blkid, "UUID", device);
783    }
784    
785    static enum lineType_e getTypeByKeyword(char * keyword,
786     struct configFileInfo * cfi) {
787        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
788     if (cfi->caseInsensitive) {
789        if (!strcasecmp(keyword, kw->key))
790                    return kw->type;
791     } else {
792        if (!strcmp(keyword, kw->key))
793            return kw->type;
794     }
795        }
796        return LT_UNKNOWN;
797    }
798    
799    static struct singleLine * getLineByType(enum lineType_e type,
800     struct singleLine * line) {
801        dbgPrintf("getLineByType(%d): ", type);
802        for (; line; line = line->next) {
803     dbgPrintf("%d:%s ", line->type,
804      line->numElements ? line->elements[0].item : "(empty)");
805     if (line->type & type) break;
806        }
807        dbgPrintf(line ? "\n" : " (failed)\n");
808        return line;
809    }
810    
811  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
812      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
813          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
814          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
815              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 821  static int isBracketedTitle(struct singl
821      return 0;      return 0;
822  }  }
823    
824  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
825                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
826      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
827   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;  
828  }  }
829    
830  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
831  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
832      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
833      char * title;      char * title = NULL;
834      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
835      title++;   title = strdup(line->elements[0].item);
836      *(title + strlen(title) - 1) = '\0';   title++;
837     *(title + strlen(title) - 1) = '\0';
838        } else if (line->type == LT_MENUENTRY)
839     title = strdup(line->elements[1].item);
840        else
841     return NULL;
842      return title;      return title;
843  }  }
844    
# Line 389  static void lineInit(struct singleLine * Line 880  static void lineInit(struct singleLine *
880      line->next = NULL;      line->next = NULL;
881  }  }
882    
883  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
884      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
885    
886        newLine->indent = strdup(line->indent);
887        newLine->next = NULL;
888        newLine->type = line->type;
889        newLine->numElements = line->numElements;
890        newLine->elements = malloc(sizeof(*newLine->elements) *
891           newLine->numElements);
892    
893        for (int i = 0; i < newLine->numElements; i++) {
894     newLine->elements[i].indent = strdup(line->elements[i].indent);
895     newLine->elements[i].item = strdup(line->elements[i].item);
896        }
897    
898        return newLine;
899    }
900    
901    static void lineFree(struct singleLine * line) {
902      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
903    
904      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
905   free(line->elements[i].item);   free(line->elements[i].item);
906   free(line->elements[i].indent);   free(line->elements[i].indent);
907      }      }
# Line 405  static void lineFree(struct singleLine * Line 912  static void lineFree(struct singleLine *
912    
913  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
914       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
915      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
916    
917      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
918     /* Need to handle this, because we strip the quotes from
919     * menuentry when read it. */
920     if (line->type == LT_MENUENTRY && i == 1) {
921        if(!isquote(*line->elements[i].item))
922     fprintf(out, "\'%s\'", line->elements[i].item);
923        else
924     fprintf(out, "%s", line->elements[i].item);
925        fprintf(out, "%s", line->elements[i].indent);
926    
927        continue;
928     }
929    
930   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
931      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
932    
933   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
934   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
935        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
936      }      }
937    
938      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 951  static int getNextLine(char ** bufPtr, s
951      char * chptr;      char * chptr;
952      int elementsAlloced = 0;      int elementsAlloced = 0;
953      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
954      int first = 1;      int first = 1;
     int i;  
955    
956      lineFree(line);      lineFree(line);
957    
# Line 489  static int getNextLine(char ** bufPtr, s Line 1005  static int getNextLine(char ** bufPtr, s
1005      if (!line->numElements)      if (!line->numElements)
1006   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
1007      else {      else {
1008   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
1009      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;  
               
1010              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
1011               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
1012              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 1020  static int getNextLine(char ** bufPtr, s
1020      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
1021   char * fullLine;   char * fullLine;
1022   int len;   int len;
  int i;  
1023    
1024   len = strlen(line->indent);   len = strlen(line->indent);
1025   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
1026      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
1027     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1028    
# Line 522  static int getNextLine(char ** bufPtr, s Line 1031  static int getNextLine(char ** bufPtr, s
1031   free(line->indent);   free(line->indent);
1032   line->indent = fullLine;   line->indent = fullLine;
1033    
1034   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1035      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1036      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1037      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 1041  static int getNextLine(char ** bufPtr, s
1041   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
1042   line->numElements = 0;   line->numElements = 0;
1043      }      }
1044     } else {
1045     struct keywordTypes *kw;
1046    
1047     kw = getKeywordByType(line->type, cfi);
1048    
1049     /* space isn't the only separator, we need to split
1050     * elements up more
1051     */
1052     if (!isspace(kw->separatorChar)) {
1053        char indent[2] = "";
1054        indent[0] = kw->separatorChar;
1055        for (int i = 1; i < line->numElements; i++) {
1056     char *p;
1057     int numNewElements;
1058    
1059     numNewElements = 0;
1060     p = line->elements[i].item;
1061     while (*p != '\0') {
1062     if (*p == kw->separatorChar)
1063     numNewElements++;
1064     p++;
1065     }
1066     if (line->numElements + numNewElements >= elementsAlloced) {
1067     elementsAlloced += numNewElements + 5;
1068     line->elements = realloc(line->elements,
1069        sizeof(*line->elements) * elementsAlloced);
1070     }
1071    
1072     for (int j = line->numElements; j > i; j--) {
1073     line->elements[j + numNewElements] = line->elements[j];
1074     }
1075     line->numElements += numNewElements;
1076    
1077     p = line->elements[i].item;
1078     while (*p != '\0') {
1079    
1080     while (*p != kw->separatorChar && *p != '\0') p++;
1081     if (*p == '\0') {
1082     break;
1083     }
1084    
1085     line->elements[i + 1].indent = line->elements[i].indent;
1086     line->elements[i].indent = strdup(indent);
1087     *p++ = '\0';
1088     i++;
1089     line->elements[i].item = strdup(p);
1090     }
1091        }
1092     }
1093   }   }
1094      }      }
1095    
1096      return 0;      return 0;
1097  }  }
1098    
1099    static int isnumber(const char *s)
1100    {
1101        int i;
1102        for (i = 0; s[i] != '\0'; i++)
1103     if (s[i] < '0' || s[i] > '9')
1104        return 0;
1105        return i;
1106    }
1107    
1108  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1109        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1110      int in;      int in;
# Line 549  static struct grubConfig * readConfig(co Line 1116  static struct grubConfig * readConfig(co
1116      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1117      char * end;      char * end;
1118      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1119      int i, len;      int len;
1120      char * buf;      char * buf;
1121    
1122      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1123            printf("Could not find bootloader configuration\n");
1124            exit(1);
1125        } else if (!strcmp(inName, "-")) {
1126   in = 0;   in = 0;
1127      } else {      } else {
1128   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1165  static struct grubConfig * readConfig(co
1165      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1166   }   }
1167    
1168   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1169      sawEntry = 1;      sawEntry = 1;
1170      if (!entry) {      if (!entry) {
1171   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1181  static struct grubConfig * readConfig(co
1181      entry->next = NULL;      entry->next = NULL;
1182   }   }
1183    
1184   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1185      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1186      defaultLine = line;      dbgPrintf("%s", line->indent);
1187        for (int i = 0; i < line->numElements; i++)
1188     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1189        dbgPrintf("\n");
1190        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1191        if (kwType && line->numElements == 3 &&
1192        !strcmp(line->elements[1].item, kwType->key) &&
1193        !is_special_grub2_variable(line->elements[2].item)) {
1194     dbgPrintf("Line sets default config\n");
1195     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1196     defaultLine = line;
1197        }
1198    
1199            } else if (iskernel(line->type)) {
1200        /* if by some freak chance this is multiboot and the "module"
1201         * lines came earlier in the template, make sure to use LT_HYPER
1202         * instead of LT_KERNEL now
1203         */
1204        if (entry && entry->multiboot)
1205     line->type = LT_HYPER;
1206    
1207          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1208        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1209         * instead, now that we know this is a multiboot entry.
1210         * This only applies to grub, but that's the only place we
1211         * should find LT_MBMODULE lines anyway.
1212         */
1213        for (struct singleLine *l = entry->lines; l; l = l->next) {
1214     if (l->type == LT_HYPER)
1215        break;
1216     else if (iskernel(l->type)) {
1217        l->type = LT_HYPER;
1218        break;
1219     }
1220        }
1221              entry->multiboot = 1;              entry->multiboot = 1;
1222    
1223     } else if (line->type == LT_HYPER) {
1224        entry->multiboot = 1;
1225    
1226   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1227      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1228      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1229   } else if (line->type == LT_TITLE && line->numElements > 1) {  
1230      /* make the title a single argument (undoing our parsing) */   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1231                    (line->type == LT_TITLE && line->numElements > 1)) {
1232        /* make the title/default a single argument (undoing our parsing) */
1233      len = 0;      len = 0;
1234      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1235   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1236   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1237      }      }
1238      buf = malloc(len + 1);      buf = malloc(len + 1);
1239      *buf = '\0';      *buf = '\0';
1240    
1241      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1242   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1243   free(line->elements[i].item);   free(line->elements[i].item);
1244    
# Line 643  static struct grubConfig * readConfig(co Line 1252  static struct grubConfig * readConfig(co
1252      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1253      line->elements[1].item = buf;      line->elements[1].item = buf;
1254      line->numElements = 2;      line->numElements = 2;
1255     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1256        /* let --remove-kernel="TITLE=what" work */
1257        len = 0;
1258        char *extras;
1259        char *title;
1260    
1261        for (int i = 1; i < line->numElements; i++) {
1262     len += strlen(line->elements[i].item);
1263     len += strlen(line->elements[i].indent);
1264        }
1265        buf = malloc(len + 1);
1266        *buf = '\0';
1267    
1268        /* allocate mem for extra flags. */
1269        extras = malloc(len + 1);
1270        *extras = '\0';
1271    
1272        /* get title. */
1273        for (int i = 0; i < line->numElements; i++) {
1274     if (!strcmp(line->elements[i].item, "menuentry"))
1275        continue;
1276     if (isquote(*line->elements[i].item))
1277        title = line->elements[i].item + 1;
1278     else
1279        title = line->elements[i].item;
1280    
1281     len = strlen(title);
1282            if (isquote(title[len-1])) {
1283        strncat(buf, title,len-1);
1284        break;
1285     } else {
1286        strcat(buf, title);
1287        strcat(buf, line->elements[i].indent);
1288     }
1289        }
1290    
1291        /* get extras */
1292        int count = 0;
1293        for (int i = 0; i < line->numElements; i++) {
1294     if (count >= 2) {
1295        strcat(extras, line->elements[i].item);
1296        strcat(extras, line->elements[i].indent);
1297     }
1298    
1299     if (!strcmp(line->elements[i].item, "menuentry"))
1300        continue;
1301    
1302     /* count ' or ", there should be two in menuentry line. */
1303     if (isquote(*line->elements[i].item))
1304        count++;
1305    
1306     len = strlen(line->elements[i].item);
1307    
1308     if (isquote(line->elements[i].item[len -1]))
1309        count++;
1310    
1311     /* ok, we get the final ' or ", others are extras. */
1312                }
1313        line->elements[1].indent =
1314     line->elements[line->numElements - 2].indent;
1315        line->elements[1].item = buf;
1316        line->elements[2].indent =
1317     line->elements[line->numElements - 2].indent;
1318        line->elements[2].item = extras;
1319        line->numElements = 3;
1320   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1321      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1322         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 1325  static struct grubConfig * readConfig(co
1325      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1326   int last, len;   int last, len;
1327    
1328   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1329      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1330     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1331    
1332   last = line->numElements - 1;   last = line->numElements - 1;
1333   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1334   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1335      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1336      }      }
1337     }
1338    
1339     if (line->type == LT_DEFAULT && line->numElements == 2) {
1340        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1341        defaultLine = line;
1342   }   }
1343    
1344   /* 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 1358  static struct grubConfig * readConfig(co
1358   movedLine = 1;   movedLine = 1;
1359   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1360   }   }
1361    
1362   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1363     which was moved, drop it. */     which was moved, drop it. */
1364   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 1374  static struct grubConfig * readConfig(co
1374   entry->lines = line;   entry->lines = line;
1375      else      else
1376   last->next = line;   last->next = line;
1377        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1378    
1379        /* we could have seen this outside of an entry... if so, we
1380         * ignore it like any other line we don't grok */
1381        if (line->type == LT_ENTRY_END && sawEntry)
1382     sawEntry = 0;
1383   } else {   } else {
1384      if (!cfg->theLines)      if (!cfg->theLines)
1385   cfg->theLines = line;   cfg->theLines = line;
1386      else {      else
1387   last->next = line;   last->next = line;
1388      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1389   }   }
1390    
1391   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1393  static struct grubConfig * readConfig(co
1393    
1394      free(incoming);      free(incoming);
1395    
1396        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1397      if (defaultLine) {      if (defaultLine) {
1398   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1399        cfi->defaultSupportSaved &&
1400        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1401     cfg->cfi->defaultIsSaved = 1;
1402     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1403     if (cfg->cfi->getEnv) {
1404        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1405        if (defTitle) {
1406     int index = 0;
1407     if (isnumber(defTitle)) {
1408        index = atoi(defTitle);
1409        entry = findEntryByIndex(cfg, index);
1410     } else {
1411        entry = findEntryByTitle(cfg, defTitle, &index);
1412     }
1413     if (entry)
1414        cfg->defaultImage = index;
1415        }
1416     }
1417     } else if (cfi->defaultIsVariable) {
1418        char *value = defaultLine->elements[2].item;
1419        while (*value && (*value == '"' || *value == '\'' ||
1420        *value == ' ' || *value == '\t'))
1421     value++;
1422        cfg->defaultImage = strtol(value, &end, 10);
1423        while (*end && (*end == '"' || *end == '\'' ||
1424        *end == ' ' || *end == '\t'))
1425     end++;
1426        if (*end) cfg->defaultImage = -1;
1427     } else if (cfi->defaultSupportSaved &&
1428   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1429      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1430   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1431      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1432      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1433   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1434      i = 0;      int i = 0;
1435      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1436   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1437      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1445  static struct grubConfig * readConfig(co
1445                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1446                  }                  }
1447   i++;   i++;
1448     entry = NULL;
1449      }      }
1450    
1451      if (entry) cfg->defaultImage = i;      if (entry){
1452            cfg->defaultImage = i;
1453        }else{
1454            cfg->defaultImage = -1;
1455        }
1456   }   }
1457        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1458     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1459     if (defTitle) {
1460        int index = 0;
1461        if (isnumber(defTitle)) {
1462     index = atoi(defTitle);
1463     entry = findEntryByIndex(cfg, index);
1464        } else {
1465     entry = findEntryByTitle(cfg, defTitle, &index);
1466        }
1467        if (entry)
1468     cfg->defaultImage = index;
1469     }
1470        } else {
1471            cfg->defaultImage = 0;
1472      }      }
1473    
1474      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1484  static void writeDefault(FILE * out, cha
1484    
1485      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1486   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1487      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1488     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1489     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1490        char *title;
1491        entry = findEntryByIndex(cfg, cfg->defaultImage);
1492        line = getLineByType(LT_MENUENTRY, entry->lines);
1493        if (!line)
1494     line = getLineByType(LT_TITLE, entry->lines);
1495        if (line) {
1496     title = extractTitle(line);
1497     if (title)
1498        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1499        }
1500     }
1501        } else if (cfg->defaultImage > -1) {
1502   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1503      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1504      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1505     cfg->defaultImage);
1506        } else {
1507     fprintf(out, "%sdefault%s%d\n", indent, separator,
1508     cfg->defaultImage);
1509        }
1510   } else {   } else {
1511      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1512    
# Line 769  static void writeDefault(FILE * out, cha Line 1523  static void writeDefault(FILE * out, cha
1523    
1524      if (!entry) return;      if (!entry) return;
1525    
1526      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1527    
1528      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1529   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1557  static int writeConfig(struct grubConfig
1557      int rc;      int rc;
1558    
1559      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1560         directory to / */         directory to the dir of the symlink */
1561      rc = chdir("/");      char *dir = strdupa(outName);
1562        rc = chdir(dirname(dir));
1563      do {      do {
1564   buf = alloca(len + 1);   buf = alloca(len + 1);
1565   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1566   if (rc == len) len += 256;   if (rc == len) len += 256;
1567      } while (rc == len);      } while (rc == len);
1568            
# Line 843  static int writeConfig(struct grubConfig Line 1597  static int writeConfig(struct grubConfig
1597      }      }
1598    
1599      line = cfg->theLines;      line = cfg->theLines;
1600        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1601      while (line) {      while (line) {
1602   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1603     line->numElements == 3 &&
1604     !strcmp(line->elements[1].item, defaultKw->key) &&
1605     !is_special_grub2_variable(line->elements[2].item)) {
1606        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1607        needs &= ~MAIN_DEFAULT;
1608     } else if (line->type == LT_DEFAULT) {
1609      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1610      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1611   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1673  static int numEntries(struct grubConfig
1673      return i;      return i;
1674  }  }
1675    
1676  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1677    int skipRemoved, int flags) {  {
1678      struct singleLine * line;      int fd;
1679      char * fullName;      char buf[65536];
1680      int i;      char *devname;
1681      struct stat sb, sb2;      char *chptr;
1682      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1683    
1684      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1685      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1686                        _PATH_MOUNTED, strerror(errno));
1687      if (!line) return 0;          return NULL;
1688      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1689    
1690      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1691        if (rc <= 0) {
1692            fprintf(stderr, "grubby: failed to read %s: %s\n",
1693                    _PATH_MOUNTED, strerror(errno));
1694            close(fd);
1695            return NULL;
1696        }
1697        close(fd);
1698        buf[rc] = '\0';
1699        chptr = buf;
1700    
1701        char *foundanswer = NULL;
1702    
1703        while (chptr && chptr != buf+rc) {
1704            devname = chptr;
1705    
1706            /*
1707             * The first column of a mtab entry is the device, but if the entry is a
1708             * special device it won't start with /, so move on to the next line.
1709             */
1710            if (*devname != '/') {
1711                chptr = strchr(chptr, '\n');
1712                if (chptr)
1713                    chptr++;
1714                continue;
1715            }
1716    
1717            /* Seek to the next space */
1718            chptr = strchr(chptr, ' ');
1719            if (!chptr) {
1720                fprintf(stderr, "grubby: error parsing %s: %s\n",
1721                        _PATH_MOUNTED, strerror(errno));
1722                return NULL;
1723            }
1724    
1725            /*
1726             * The second column of a mtab entry is the mount point, we are looking
1727             * for '/' obviously.
1728             */
1729            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1730                /* remember the last / entry in mtab */
1731               foundanswer = devname;
1732            }
1733    
1734            /* Next line */
1735            chptr = strchr(chptr, '\n');
1736            if (chptr)
1737                chptr++;
1738        }
1739    
1740        /* Return the last / entry found */
1741        if (foundanswer) {
1742            chptr = strchr(foundanswer, ' ');
1743            *chptr = '\0';
1744            return strdup(foundanswer);
1745        }
1746    
1747        return NULL;
1748    }
1749    
1750    void printEntry(struct singleEntry * entry, FILE *f) {
1751        int i;
1752        struct singleLine * line;
1753    
1754        for (line = entry->lines; line; line = line->next) {
1755     log_message(f, "DBG: %s", line->indent);
1756     for (i = 0; i < line->numElements; i++) {
1757        /* Need to handle this, because we strip the quotes from
1758         * menuentry when read it. */
1759        if (line->type == LT_MENUENTRY && i == 1) {
1760     if(!isquote(*line->elements[i].item))
1761        log_message(f, "\'%s\'", line->elements[i].item);
1762     else
1763        log_message(f, "%s", line->elements[i].item);
1764     log_message(f, "%s", line->elements[i].indent);
1765    
1766     continue;
1767        }
1768        
1769        log_message(f, "%s%s",
1770        line->elements[i].item, line->elements[i].indent);
1771     }
1772     log_message(f, "\n");
1773        }
1774    }
1775    
1776    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1777    {
1778        static int once;
1779        va_list argp, argq;
1780    
1781        va_start(argp, fmt);
1782    
1783        va_copy(argq, argp);
1784        if (!once) {
1785     log_time(NULL);
1786     log_message(NULL, "command line: %s\n", saved_command_line);
1787        }
1788        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1789        log_vmessage(NULL, fmt, argq);
1790    
1791        printEntry(entry, NULL);
1792        va_end(argq);
1793    
1794        if (!debug) {
1795     once = 1;
1796         va_end(argp);
1797     return;
1798        }
1799    
1800        if (okay) {
1801     va_end(argp);
1802     return;
1803        }
1804    
1805        if (!once)
1806     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1807        once = 1;
1808        fprintf(stderr, "DBG: Image entry failed: ");
1809        vfprintf(stderr, fmt, argp);
1810        printEntry(entry, stderr);
1811        va_end(argp);
1812    }
1813    
1814    #define beginswith(s, c) ((s) && (s)[0] == (c))
1815    
1816    static int endswith(const char *s, char c)
1817    {
1818     int slen;
1819    
1820     if (!s || !s[0])
1821     return 0;
1822     slen = strlen(s) - 1;
1823    
1824     return s[slen] == c;
1825    }
1826    
1827    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1828      int skipRemoved, int flags) {
1829        struct singleLine * line;
1830        char * fullName;
1831        int i;
1832        char * dev;
1833        char * rootspec;
1834        char * rootdev;
1835    
1836        if (skipRemoved && entry->skip) {
1837     notSuitablePrintf(entry, 0, "marked to skip\n");
1838     return 0;
1839        }
1840    
1841        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1842        if (!line) {
1843     notSuitablePrintf(entry, 0, "no line found\n");
1844     return 0;
1845        }
1846        if (line->numElements < 2) {
1847     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1848        line->numElements);
1849     return 0;
1850        }
1851    
1852        if (flags & GRUBBY_BADIMAGE_OKAY) {
1853        notSuitablePrintf(entry, 1, "\n");
1854        return 1;
1855        }
1856    
1857      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1858        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1859      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1860      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1861              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1862                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1863      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1864                line->elements[1].item + rootspec_offset);
1865        if (access(fullName, R_OK)) {
1866     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1867     return 0;
1868        }
1869      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1870   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1871      if (i < line->numElements) {      if (i < line->numElements) {
1872   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1873      } else {      } else {
1874   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1875   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1876    
1877   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1878      dev = line->elements[1].item;      dev = line->elements[1].item;
1879   } else {   } else {
1880              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1881      /* 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.
1882      line = entry->lines;       */
1883        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1884    
1885              /* failed to find one */              /* failed to find one */
1886              if (!line) return 0;              if (!line) {
1887     notSuitablePrintf(entry, 0, "no line found\n");
1888     return 0;
1889                }
1890    
1891      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1892          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1893      if (i < line->numElements)      if (i < line->numElements)
1894          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1895      else {      else {
1896     notSuitablePrintf(entry, 0, "no root= entry found\n");
1897   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1898          return 0;          return 0;
1899              }              }
1900   }   }
1901      }      }
1902    
1903      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1904   dev += 6;      if (!getpathbyspec(dev)) {
1905            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1906   /* check which device has this label */          return 0;
1907   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1908   if (!dev) return 0;   dev = getpathbyspec(dev);
1909    
1910        rootdev = findDiskForRoot();
1911        if (!rootdev) {
1912            notSuitablePrintf(entry, 0, "can't find root device\n");
1913     return 0;
1914      }      }
1915    
1916      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1917   if (stat(dev, &sb))          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1918      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1919      } else {          free(rootdev);
1920   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1921   if (*end) return 0;      }
1922    
1923        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1924            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1925     getuuidbydev(rootdev), getuuidbydev(dev));
1926     free(rootdev);
1927            return 0;
1928      }      }
     stat("/", &sb2);  
1929    
1930      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1931        notSuitablePrintf(entry, 1, "\n");
1932    
1933      return 1;      return 1;
1934  }  }
# Line 1024  struct singleEntry * findEntryByPath(str Line 1962  struct singleEntry * findEntryByPath(str
1962   }   }
1963    
1964   indexVars[i + 1] = -1;   indexVars[i + 1] = -1;
1965    
1966   i = 0;   i = 0;
1967   if (index) {   if (index) {
1968      while (i < *index) i++;      while (i < *index) {
1969      if (indexVars[i] == -1) return NULL;   i++;
1970     if (indexVars[i] == -1) return NULL;
1971        }
1972   }   }
1973    
1974   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1975   if (!entry) return NULL;   if (!entry) return NULL;
1976    
1977   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;  
   
1978   if (!line) return NULL;   if (!line) return NULL;
1979    
1980   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 2012  struct singleEntry * findEntryByPath(str
2012    
2013   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
2014      prefix = "";      prefix = "";
2015      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
2016      kernel += 6;      kernel += 6;
2017   }   }
2018    
2019   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
2020      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
2021    
2022        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
2023    
2024      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
2025                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
2026          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
2027                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
2028                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2029                      break;   else if (checkType & LT_KERNEL)
2030              }      ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2031                 line = getLineByType(ct, line);
2032              /* have to check multiboot lines too */   if (!line)
2033              if (entry->multiboot) {      break;  /* not found in this entry */
2034                  while (line && line->type != LT_MBMODULE) line = line->next;  
2035                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
2036                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
2037                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
2038                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
2039                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
2040                          break;   kernel + strlen(prefix)))
2041                  }   break;
2042              }   }
2043     if(line->type == LT_MENUENTRY &&
2044     !strcmp(line->elements[1].item, kernel))
2045        break;
2046        }
2047    
2048      i++;      /* make sure this entry has a kernel identifier; this skips
2049         * non-Linux boot entries (could find netbsd etc, though, which is
2050         * unfortunate)
2051         */
2052        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2053     break; /* found 'im! */
2054   }   }
2055    
2056   if (index) *index = i;   if (index) *index = i;
2057      }      }
2058    
2059      if (!entry) return NULL;      return entry;
2060    }
2061    
2062    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2063          int * index) {
2064        struct singleEntry * entry;
2065        struct singleLine * line;
2066        int i;
2067        char * newtitle;
2068    
2069      /* make sure this entry has a kernel identifier; this skips non-Linux      for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2070         boot entries (could find netbsd etc, though, which is unfortunate) */   if (index && i < *index)
2071      line = entry->lines;      continue;
2072      while (line && line->type != LT_KERNEL) line = line->next;   line = getLineByType(LT_TITLE, entry->lines);
2073      if (!line) {   if (!line)
2074   if (!index) index = &i;      line = getLineByType(LT_MENUENTRY, entry->lines);
2075   (*index)++;   if (!line)
2076   return findEntryByPath(config, kernel, prefix, index);      continue;
2077     newtitle = grub2ExtractTitle(line);
2078     if (!newtitle)
2079        continue;
2080     if (!strcmp(title, newtitle))
2081        break;
2082      }      }
2083    
2084        if (!entry)
2085     return NULL;
2086    
2087        if (index)
2088     *index = i;
2089      return entry;      return entry;
2090  }  }
2091    
# Line 1147  struct singleEntry * findTemplate(struct Line 2111  struct singleEntry * findTemplate(struct
2111      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2112      int index;      int index;
2113    
2114      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2115     if (cfg->cfi->getEnv) {
2116        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2117        if (defTitle) {
2118     int index = 0;
2119     if (isnumber(defTitle)) {
2120        index = atoi(defTitle);
2121        entry = findEntryByIndex(cfg, index);
2122     } else {
2123        entry = findEntryByTitle(cfg, defTitle, &index);
2124     }
2125     if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2126        cfg->defaultImage = index;
2127        if (indexPtr)
2128     *indexPtr = index;
2129        return entry;
2130     }
2131        }
2132     }
2133        } else if (cfg->defaultImage > -1) {
2134   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2135   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2136      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1200  void markRemovedImage(struct grubConfig Line 2183  void markRemovedImage(struct grubConfig
2183        const char * prefix) {        const char * prefix) {
2184      struct singleEntry * entry;      struct singleEntry * entry;
2185    
2186      if (!image) return;      if (!image)
2187     return;
2188    
2189        /* check and see if we're removing the default image */
2190        if (isdigit(*image)) {
2191     entry = findEntryByPath(cfg, image, prefix, NULL);
2192     if(entry)
2193        entry->skip = 1;
2194     return;
2195        }
2196    
2197      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2198   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 2200  void markRemovedImage(struct grubConfig
2200    
2201  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2202       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2203       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2204      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2205      int i, j;      int i, j;
2206    
2207      if (newIsDefault) {      if (newIsDefault) {
2208   config->defaultImage = 0;   config->defaultImage = 0;
2209   return;   return;
2210        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2211     if (findEntryByIndex(config, index))
2212        config->defaultImage = index;
2213     else
2214        config->defaultImage = -1;
2215     return;
2216      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2217   i = 0;   i = 0;
2218   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 2225  void setDefaultImage(struct grubConfig *
2225    
2226      /* 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
2227         changes */         changes */
2228      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2229     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2230        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2231        return;        return;
2232    
# Line 1285  void displayEntry(struct singleEntry * e Line 2284  void displayEntry(struct singleEntry * e
2284      struct singleLine * line;      struct singleLine * line;
2285      char * root = NULL;      char * root = NULL;
2286      int i;      int i;
2287        int j;
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
2288    
2289      printf("index=%d\n", index);      printf("index=%d\n", index);
2290    
2291      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2292        if (!line) {
2293            printf("non linux entry\n");
2294            return;
2295        }
2296    
2297        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2298     printf("kernel=%s\n", line->elements[1].item);
2299        else
2300     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2301    
2302      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2303   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2314  void displayEntry(struct singleEntry * e
2314   }   }
2315   printf("\"\n");   printf("\"\n");
2316      } else {      } else {
2317   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2318   if (line) {   if (line) {
2319      char * s;      char * s;
2320    
# Line 1334  void displayEntry(struct singleEntry * e Line 2338  void displayEntry(struct singleEntry * e
2338      }      }
2339    
2340      if (!root) {      if (!root) {
2341   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2342   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2343      root=line->elements[1].item;      root=line->elements[1].item;
2344      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2353  void displayEntry(struct singleEntry * e
2353   printf("root=%s\n", s);   printf("root=%s\n", s);
2354      }      }
2355    
2356      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2357    
2358      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2359   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2360        printf("initrd=");
2361     else
2362        printf("initrd=%s", prefix);
2363    
2364   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2365      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2366   printf("\n");   printf("\n");
2367      }      }
2368    
2369        line = getLineByType(LT_TITLE, entry->lines);
2370        if (line) {
2371     printf("title=%s\n", line->elements[1].item);
2372        } else {
2373     char * title;
2374     line = getLineByType(LT_MENUENTRY, entry->lines);
2375     if (line) {
2376        title = grub2ExtractTitle(line);
2377        if (title)
2378     printf("title=%s\n", title);
2379     }
2380        }
2381    
2382        for (j = 0, line = entry->lines; line; line = line->next) {
2383     if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
2384        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2385     printf("mbmodule%d=", j);
2386        else
2387     printf("mbmodule%d=%s", j, prefix);
2388    
2389        for (i = 1; i < line->numElements; i++)
2390     printf("%s%s", line->elements[i].item, line->elements[i].indent);
2391        printf("\n");
2392        j++;
2393     }
2394        }
2395    }
2396    
2397    int isSuseSystem(void) {
2398        const char * path;
2399        const static char default_path[] = "/etc/SuSE-release";
2400    
2401        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2402     path = default_path;
2403    
2404        if (!access(path, R_OK))
2405     return 1;
2406        return 0;
2407    }
2408    
2409    int isSuseGrubConf(const char * path) {
2410        FILE * grubConf;
2411        char * line = NULL;
2412        size_t len = 0, res = 0;
2413    
2414        grubConf = fopen(path, "r");
2415        if (!grubConf) {
2416            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2417     return 0;
2418        }
2419    
2420        while ((res = getline(&line, &len, grubConf)) != -1) {
2421     if (!strncmp(line, "setup", 5)) {
2422        fclose(grubConf);
2423        free(line);
2424        return 1;
2425     }
2426        }
2427    
2428        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2429          path);
2430    
2431        fclose(grubConf);
2432        free(line);
2433        return 0;
2434    }
2435    
2436    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2437        FILE * grubConf;
2438        char * line = NULL;
2439        size_t res = 0, len = 0;
2440    
2441        if (!path) return 1;
2442        if (!lbaPtr) return 1;
2443    
2444        grubConf = fopen(path, "r");
2445        if (!grubConf) return 1;
2446    
2447        while ((res = getline(&line, &len, grubConf)) != -1) {
2448     if (line[res - 1] == '\n')
2449        line[res - 1] = '\0';
2450     else if (len > res)
2451        line[res] = '\0';
2452     else {
2453        line = realloc(line, res + 1);
2454        line[res] = '\0';
2455     }
2456    
2457     if (!strncmp(line, "setup", 5)) {
2458        if (strstr(line, "--force-lba")) {
2459            *lbaPtr = 1;
2460        } else {
2461            *lbaPtr = 0;
2462        }
2463        dbgPrintf("lba: %i\n", *lbaPtr);
2464        break;
2465     }
2466        }
2467    
2468        free(line);
2469        fclose(grubConf);
2470        return 0;
2471    }
2472    
2473    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2474        FILE * grubConf;
2475        char * line = NULL;
2476        size_t res = 0, len = 0;
2477        char * lastParamPtr = NULL;
2478        char * secLastParamPtr = NULL;
2479        char installDeviceNumber = '\0';
2480        char * bounds = NULL;
2481    
2482        if (!path) return 1;
2483        if (!devicePtr) return 1;
2484    
2485        grubConf = fopen(path, "r");
2486        if (!grubConf) return 1;
2487    
2488        while ((res = getline(&line, &len, grubConf)) != -1) {
2489     if (strncmp(line, "setup", 5))
2490        continue;
2491    
2492     if (line[res - 1] == '\n')
2493        line[res - 1] = '\0';
2494     else if (len > res)
2495        line[res] = '\0';
2496     else {
2497        line = realloc(line, res + 1);
2498        line[res] = '\0';
2499     }
2500    
2501     lastParamPtr = bounds = line + res;
2502    
2503     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2504     while (!isspace(*lastParamPtr))
2505        lastParamPtr--;
2506     lastParamPtr++;
2507    
2508     secLastParamPtr = lastParamPtr - 2;
2509     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2510    
2511     if (lastParamPtr + 3 > bounds) {
2512        dbgPrintf("lastParamPtr going over boundary");
2513        fclose(grubConf);
2514        free(line);
2515        return 1;
2516     }
2517     if (!strncmp(lastParamPtr, "(hd", 3))
2518        lastParamPtr += 3;
2519     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2520    
2521     /*
2522     * Second last parameter will decide wether last parameter is
2523     * an IMAGE_DEVICE or INSTALL_DEVICE
2524     */
2525     while (!isspace(*secLastParamPtr))
2526        secLastParamPtr--;
2527     secLastParamPtr++;
2528    
2529     if (secLastParamPtr + 3 > bounds) {
2530        dbgPrintf("secLastParamPtr going over boundary");
2531        fclose(grubConf);
2532        free(line);
2533        return 1;
2534     }
2535     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2536     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2537        secLastParamPtr += 3;
2538        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2539        installDeviceNumber = *secLastParamPtr;
2540     } else {
2541        installDeviceNumber = *lastParamPtr;
2542     }
2543    
2544     *devicePtr = malloc(6);
2545     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2546     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2547     fclose(grubConf);
2548     free(line);
2549     return 0;
2550        }
2551    
2552        free(line);
2553        fclose(grubConf);
2554        return 1;
2555    }
2556    
2557    int grubGetBootFromDeviceMap(const char * device,
2558         char ** bootPtr) {
2559        FILE * deviceMap;
2560        char * line = NULL;
2561        size_t res = 0, len = 0;
2562        char * devicePtr;
2563        char * bounds = NULL;
2564        const char * path;
2565        const static char default_path[] = "/boot/grub/device.map";
2566    
2567        if (!device) return 1;
2568        if (!bootPtr) return 1;
2569    
2570        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2571     path = default_path;
2572    
2573        dbgPrintf("opening grub device.map file from: %s\n", path);
2574        deviceMap = fopen(path, "r");
2575        if (!deviceMap)
2576     return 1;
2577    
2578        while ((res = getline(&line, &len, deviceMap)) != -1) {
2579            if (!strncmp(line, "#", 1))
2580        continue;
2581    
2582     if (line[res - 1] == '\n')
2583        line[res - 1] = '\0';
2584     else if (len > res)
2585        line[res] = '\0';
2586     else {
2587        line = realloc(line, res + 1);
2588        line[res] = '\0';
2589     }
2590    
2591     devicePtr = line;
2592     bounds = line + res;
2593    
2594     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2595        devicePtr++;
2596     dbgPrintf("device: %s\n", devicePtr);
2597    
2598     if (!strncmp(devicePtr, device, strlen(device))) {
2599        devicePtr += strlen(device);
2600        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2601            devicePtr++;
2602    
2603        *bootPtr = strdup(devicePtr);
2604        break;
2605     }
2606        }
2607    
2608        free(line);
2609        fclose(deviceMap);
2610        return 0;
2611    }
2612    
2613    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2614        char * grubDevice;
2615    
2616        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2617     dbgPrintf("error looking for grub installation device\n");
2618        else
2619     dbgPrintf("grubby installation device: %s\n", grubDevice);
2620    
2621        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2622     dbgPrintf("error looking for grub boot device\n");
2623        else
2624     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2625    
2626        free(grubDevice);
2627        return 0;
2628    }
2629    
2630    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2631        /*
2632         * This SuSE grub configuration file at this location is not your average
2633         * grub configuration file, but instead the grub commands used to setup
2634         * grub on that system.
2635         */
2636        const char * path;
2637        const static char default_path[] = "/etc/grub.conf";
2638    
2639        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2640     path = default_path;
2641    
2642        if (!isSuseGrubConf(path)) return 1;
2643    
2644        if (lbaPtr) {
2645            *lbaPtr = 0;
2646            if (suseGrubConfGetLba(path, lbaPtr))
2647                return 1;
2648        }
2649    
2650        if (bootPtr) {
2651            *bootPtr = NULL;
2652            suseGrubConfGetBoot(path, bootPtr);
2653        }
2654    
2655        return 0;
2656  }  }
2657    
2658  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2662  int parseSysconfigGrub(int * lbaPtr, cha
2662      char * start;      char * start;
2663      char * param;      char * param;
2664    
2665      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2666      if (!in) return 1;      if (!in) return 1;
2667    
2668      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2703  int parseSysconfigGrub(int * lbaPtr, cha
2703  }  }
2704    
2705  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2706      char * boot;      char * boot = NULL;
2707      int lba;      int lba;
2708    
2709      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2710   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2711   if (boot) printf("boot=%s\n", boot);      free(boot);
2712        return;
2713     }
2714        } else {
2715            if (parseSysconfigGrub(&lba, &boot)) {
2716        free(boot);
2717        return;
2718     }
2719        }
2720    
2721        if (lba) printf("lba\n");
2722        if (boot) {
2723     printf("boot=%s\n", boot);
2724     free(boot);
2725      }      }
2726  }  }
2727    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2737  int displayInfo(struct grubConfig * conf
2737   return 1;   return 1;
2738      }      }
2739    
2740      /* 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
2741         be a better way */         be a better way */
2742      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2743   dumpSysconfigGrub();   dumpSysconfigGrub();
2744      } else {      } else {
2745   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2746   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2747      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2748   }   }
2749    
2750   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2751   if (line) printf("lba\n");   if (line) printf("lba\n");
2752      }      }
2753    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2762  int displayInfo(struct grubConfig * conf
2762      return 0;      return 0;
2763  }  }
2764    
2765    struct singleLine * addLineTmpl(struct singleEntry * entry,
2766     struct singleLine * tmplLine,
2767     struct singleLine * prevLine,
2768     const char * val,
2769     struct configFileInfo * cfi)
2770    {
2771        struct singleLine * newLine = lineDup(tmplLine);
2772    
2773        if (isEfi && cfi == &grub2ConfigType) {
2774     enum lineType_e old = newLine->type;
2775     newLine->type = preferredLineType(newLine->type, cfi);
2776     if (old != newLine->type)
2777        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2778        }
2779    
2780        if (val) {
2781     /* override the inherited value with our own.
2782     * This is a little weak because it only applies to elements[1]
2783     */
2784     if (newLine->numElements > 1)
2785        removeElement(newLine, 1);
2786     insertElement(newLine, val, 1, cfi);
2787    
2788     /* but try to keep the rootspec from the template... sigh */
2789     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2790        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2791        if (rootspec != NULL) {
2792     free(newLine->elements[1].item);
2793     newLine->elements[1].item =
2794        sdupprintf("%s%s", rootspec, val);
2795        }
2796     }
2797        }
2798    
2799        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2800          newLine->elements[0].item : "");
2801    
2802        if (!entry->lines) {
2803     /* first one on the list */
2804     entry->lines = newLine;
2805        } else if (prevLine) {
2806     /* add after prevLine */
2807     newLine->next = prevLine->next;
2808     prevLine->next = newLine;
2809        }
2810    
2811        return newLine;
2812    }
2813    
2814  /* val may be NULL */  /* val may be NULL */
2815  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2816       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2817       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2818       char * val) {       const char * val) {
2819      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2820      int i;      struct keywordTypes * kw;
2821        struct singleLine tmpl;
2822    
2823      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2824   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2825      if (type != LT_TITLE || !cfi->titleBracketed)       */
2826          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2827     /* we're doing a bracketed title (zipl) */
2828     tmpl.type = type;
2829     tmpl.numElements = 1;
2830     tmpl.elements = alloca(sizeof(*tmpl.elements));
2831     tmpl.elements[0].item = alloca(strlen(val)+3);
2832     sprintf(tmpl.elements[0].item, "[%s]", val);
2833     tmpl.elements[0].indent = "";
2834     val = NULL;
2835        } else if (type == LT_MENUENTRY) {
2836     char *lineend = "--class gnu-linux --class gnu --class os {";
2837     if (!val) {
2838        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2839        abort();
2840     }
2841     kw = getKeywordByType(type, cfi);
2842     if (!kw) {
2843        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2844        abort();
2845     }
2846     tmpl.indent = "";
2847     tmpl.type = type;
2848     tmpl.numElements = 3;
2849     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2850     tmpl.elements[0].item = kw->key;
2851     tmpl.elements[0].indent = alloca(2);
2852     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2853     tmpl.elements[1].item = (char *)val;
2854     tmpl.elements[1].indent = alloca(2);
2855     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2856     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2857     strcpy(tmpl.elements[2].item, lineend);
2858     tmpl.elements[2].indent = "";
2859        } else {
2860     kw = getKeywordByType(type, cfi);
2861     if (!kw) {
2862        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2863        abort();
2864     }
2865     tmpl.type = type;
2866     tmpl.numElements = val ? 2 : 1;
2867     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2868     tmpl.elements[0].item = kw->key;
2869     tmpl.elements[0].indent = alloca(2);
2870     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2871     if (val) {
2872        tmpl.elements[1].item = (char *)val;
2873        tmpl.elements[1].indent = "";
2874     }
2875        }
2876    
2877      /* 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
2878         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2879         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
2880         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2881         differently from the rest) */         differently from the rest) */
2882      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2883   line = entry->lines;   if (line->numElements) prev = line;
2884   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2885   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;  
2886      }      }
2887    
2888      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2889          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2890          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2891          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2892          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2893          line->elements[0].indent = malloc(2);   else
2894          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2895          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2896             if (menuEntry)
2897          if (val) {      tmpl.indent = "\t";
2898              line->elements[1].item = val;   else if (prev == entry->lines)
2899              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2900          }   else
2901      } 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("");  
2902      }      }
2903    
2904      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2905  }  }
2906    
2907  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2926  void removeLine(struct singleEntry * ent
2926      free(line);      free(line);
2927  }  }
2928    
2929    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2930    {
2931        struct singleLine newLine = {
2932     .indent = tmplLine->indent,
2933     .type = tmplLine->type,
2934     .next = tmplLine->next,
2935        };
2936        int firstQuotedItem = -1;
2937        int quoteLen = 0;
2938        int j;
2939        int element = 0;
2940        char *c;
2941    
2942        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2943        strcpy(c, tmplLine->elements[0].item);
2944        insertElement(&newLine, c, element++, cfi);
2945        free(c);
2946        c = NULL;
2947    
2948        for (j = 1; j < tmplLine->numElements; j++) {
2949     if (firstQuotedItem == -1) {
2950        quoteLen += strlen(tmplLine->elements[j].item);
2951        
2952        if (isquote(tmplLine->elements[j].item[0])) {
2953     firstQuotedItem = j;
2954            quoteLen += strlen(tmplLine->elements[j].indent);
2955        } else {
2956     c = malloc(quoteLen + 1);
2957     strcpy(c, tmplLine->elements[j].item);
2958     insertElement(&newLine, c, element++, cfi);
2959     free(c);
2960     quoteLen = 0;
2961        }
2962     } else {
2963        int itemlen = strlen(tmplLine->elements[j].item);
2964        quoteLen += itemlen;
2965        quoteLen += strlen(tmplLine->elements[j].indent);
2966        
2967        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2968     c = malloc(quoteLen + 1);
2969     c[0] = '\0';
2970     for (int i = firstQuotedItem; i < j+1; i++) {
2971        strcat(c, tmplLine->elements[i].item);
2972        strcat(c, tmplLine->elements[i].indent);
2973     }
2974     insertElement(&newLine, c, element++, cfi);
2975     free(c);
2976    
2977     firstQuotedItem = -1;
2978     quoteLen = 0;
2979        }
2980     }
2981        }
2982        while (tmplLine->numElements)
2983     removeElement(tmplLine, 0);
2984        if (tmplLine->elements)
2985     free(tmplLine->elements);
2986    
2987        tmplLine->numElements = newLine.numElements;
2988        tmplLine->elements = newLine.elements;
2989    }
2990    
2991    static void insertElement(struct singleLine * line,
2992      const char * item, int insertHere,
2993      struct configFileInfo * cfi)
2994    {
2995        struct keywordTypes * kw;
2996        char indent[2] = "";
2997    
2998        /* sanity check */
2999        if (insertHere > line->numElements) {
3000     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
3001      insertHere, line->numElements);
3002     insertHere = line->numElements;
3003        }
3004    
3005        line->elements = realloc(line->elements, (line->numElements + 1) *
3006         sizeof(*line->elements));
3007        memmove(&line->elements[insertHere+1],
3008        &line->elements[insertHere],
3009        (line->numElements - insertHere) *
3010        sizeof(*line->elements));
3011        line->elements[insertHere].item = strdup(item);
3012    
3013        kw = getKeywordByType(line->type, cfi);
3014    
3015        if (line->numElements == 0) {
3016     indent[0] = '\0';
3017        } else if (insertHere == 0) {
3018     indent[0] = kw->nextChar;
3019        } else if (kw->separatorChar != '\0') {
3020     indent[0] = kw->separatorChar;
3021        } else {
3022     indent[0] = ' ';
3023        }
3024    
3025        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
3026     /* move the end-of-line forward */
3027     line->elements[insertHere].indent =
3028        line->elements[insertHere-1].indent;
3029     line->elements[insertHere-1].indent = strdup(indent);
3030        } else {
3031     line->elements[insertHere].indent = strdup(indent);
3032        }
3033    
3034        line->numElements++;
3035    
3036        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
3037          line->elements[0].item,
3038          line->elements[insertHere].item,
3039          line->elements[insertHere].indent,
3040          insertHere);
3041    }
3042    
3043    static void removeElement(struct singleLine * line, int removeHere) {
3044        int i;
3045    
3046        /* sanity check */
3047        if (removeHere >= line->numElements) return;
3048    
3049        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
3050          removeHere, line->elements[removeHere].item);
3051    
3052        free(line->elements[removeHere].item);
3053    
3054        if (removeHere > 1) {
3055     /* previous argument gets this argument's post-indentation */
3056     free(line->elements[removeHere-1].indent);
3057     line->elements[removeHere-1].indent =
3058        line->elements[removeHere].indent;
3059        } else {
3060     free(line->elements[removeHere].indent);
3061        }
3062    
3063        /* now collapse the array, but don't bother to realloc smaller */
3064        for (i = removeHere; i < line->numElements - 1; i++)
3065     line->elements[i] = line->elements[i + 1];
3066    
3067        line->numElements--;
3068    }
3069    
3070  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
3071      char * first, * second;      char * first, * second;
3072      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 3089  int updateActualImage(struct grubConfig
3089      struct singleEntry * entry;      struct singleEntry * entry;
3090      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
3091      int index = 0;      int index = 0;
3092      int i, j, k;      int i, k;
3093      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
3094      const char ** arg;      const char ** arg;
3095      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
3096      int firstElement;      int firstElement;
3097      int *usedElements, *usedArgs;      int *usedElements;
3098        int doreplace;
3099    
3100      if (!image) return 0;      if (!image) return 0;
3101    
# Line 1609  int updateActualImage(struct grubConfig Line 3122  int updateActualImage(struct grubConfig
3122   }   }
3123      }      }
3124    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
3125    
3126      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
3127   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
3128    
3129      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3130   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
3131    
3132      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
3133    
3134      k = 0;   if (multibootArgs && !entry->multiboot)
3135      for (arg = newArgs; *arg; arg++)      continue;
3136          k++;  
3137      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
3138     * LT_KERNELARGS, use that.  Otherwise use
3139     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
3140     */
3141     if (useKernelArgs) {
3142        line = getLineByType(LT_KERNELARGS, entry->lines);
3143        if (!line) {
3144     /* no LT_KERNELARGS, need to add it */
3145     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
3146           cfg->secondaryIndent, NULL);
3147        }
3148        firstElement = 1;
3149    
3150      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
3151   index++;      line = getLineByType(LT_HYPER, entry->lines);
3152        if (!line) {
3153     /* a multiboot entry without LT_HYPER? */
3154     continue;
3155        }
3156        firstElement = 2;
3157    
3158   line = entry->lines;   } else {
3159   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3160   if (!line) continue;      if (!line) {
3161   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3162     continue;
3163          if (entry->multiboot && !multibootArgs) {      }
3164              /* first mb module line is the real kernel */      firstElement = 2;
3165              while (line && line->type != LT_MBMODULE) line = line->next;   }
3166              firstElement = 2;  
3167          } else if (useKernelArgs) {   /* handle the elilo case which does:
3168      while (line && line->type != LT_KERNELARGS) line = line->next;   *   append="hypervisor args -- kernel args"
3169      firstElement = 1;   */
3170     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
3171        /* this is a multiboot entry, make sure there's
3172         * -- on the args line
3173         */
3174        for (i = firstElement; i < line->numElements; i++) {
3175     if (!strcmp(line->elements[i].item, "--"))
3176        break;
3177        }
3178        if (i == line->numElements) {
3179     /* assume all existing args are kernel args,
3180     * prepend -- to make it official
3181     */
3182     insertElement(line, "--", firstElement, cfg->cfi);
3183     i = firstElement;
3184        }
3185        if (!multibootArgs) {
3186     /* kernel args start after the -- */
3187     firstElement = i + 1;
3188        }
3189     } else if (cfg->cfi->mbConcatArgs) {
3190        /* this is a non-multiboot entry, remove hyper args */
3191        for (i = firstElement; i < line->numElements; i++) {
3192     if (!strcmp(line->elements[i].item, "--"))
3193        break;
3194        }
3195        if (i < line->numElements) {
3196     /* remove args up to -- */
3197     while (strcmp(line->elements[firstElement].item, "--"))
3198        removeElement(line, firstElement);
3199     /* remove -- */
3200     removeElement(line, firstElement);
3201        }
3202   }   }
3203    
3204   if (!line && useKernelArgs) {          usedElements = calloc(line->numElements, sizeof(*usedElements));
     /* no append in there, need to add it */  
     line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);  
  }  
3205    
3206          usedElements = calloc(line->numElements, sizeof(int));   for (k = 0, arg = newArgs; *arg; arg++, k++) {
3207    
3208          k = 0;      doreplace = 1;
  for (arg = newArgs; *arg; arg++) {  
             if (usedArgs[k]) {  
                 k++;  
                 continue;  
             }  
3209      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
3210     if (multibootArgs && cfg->cfi->mbConcatArgs &&
3211        !strcmp(line->elements[i].item, "--"))
3212     {
3213        /* reached the end of hyper args, insert here */
3214        doreplace = 0;
3215        break;  
3216     }
3217                  if (usedElements[i])                  if (usedElements[i])
3218                      continue;                      continue;
3219   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3220                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3221      break;      break;
3222                  }                  }
3223              }              }
     chptr = strchr(*arg, '=');  
3224    
3225      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
3226   /* replace */   /* direct replacement */
3227   free(line->elements[i].item);   free(line->elements[i].item);
3228   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("");  
  }  
3229    
3230   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
3231   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
3232      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
3233   /* append */   if (rootLine) {
3234   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
3235   (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(" ");  
3236   } else {   } else {
3237      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
3238         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
3239   }   }
3240        }
3241    
3242   line->numElements++;      else {
3243     /* insert/append */
3244     insertElement(line, *arg, i, cfg->cfi);
3245     usedElements = realloc(usedElements, line->numElements *
3246           sizeof(*usedElements));
3247     memmove(&usedElements[i + 1], &usedElements[i],
3248     line->numElements - i - 1);
3249     usedElements[i] = 1;
3250    
3251   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
3252     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
3253     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
3254   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
3255      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
3256      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
3257   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
3258   }   }
3259      }      }
             k++;  
3260   }   }
3261    
3262          free(usedElements);          free(usedElements);
3263    
  /* 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? */  
3264   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
3265      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3266   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3267        !strcmp(line->elements[i].item, "--"))
3268        /* reached the end of hyper args, stop here */
3269        break;
3270     if (!argMatch(line->elements[i].item, *arg)) {
3271        removeElement(line, i);
3272      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;  
3273   }   }
3274        }
3275   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3276        if (useRoot && !strncmp(*arg, "root=", 5)) {
3277   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3278      line->elements[j - 1] = line->elements[j];   if (rootLine)
3279        removeLine(entry, rootLine);
  line->numElements--;  
3280      }      }
3281   }   }
3282    
# Line 1760  int updateActualImage(struct grubConfig Line 3287  int updateActualImage(struct grubConfig
3287   }   }
3288      }      }
3289    
     free(usedArgs);  
3290      free(newArgs);      free(newArgs);
3291      free(oldArgs);      free(oldArgs);
3292    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3312  int updateImage(struct grubConfig * cfg,
3312      return rc;      return rc;
3313  }  }
3314    
3315    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3316     const char * image, const char * prefix, const char * initrd,
3317     const char * title) {
3318        struct singleEntry * entry;
3319        struct singleLine * line, * kernelLine, *endLine = NULL;
3320        int index = 0;
3321    
3322        if (!image) return 0;
3323    
3324        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3325            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3326            if (!kernelLine) continue;
3327    
3328     /* if title is supplied, the entry's title must match it. */
3329     if (title) {
3330        char *linetitle;
3331    
3332        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3333        if (!line)
3334     continue;
3335    
3336        linetitle = extractTitle(line);
3337        if (!linetitle)
3338     continue;
3339        if (strcmp(title, linetitle)) {
3340     free(linetitle);
3341     continue;
3342        }
3343        free(linetitle);
3344     }
3345    
3346            if (prefix) {
3347                int prefixLen = strlen(prefix);
3348                if (!strncmp(initrd, prefix, prefixLen))
3349                    initrd += prefixLen;
3350            }
3351     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3352     if (endLine)
3353        removeLine(entry, endLine);
3354            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3355     kernelLine->indent, initrd);
3356            if (!line)
3357        return 1;
3358     if (endLine) {
3359        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3360                if (!line)
3361     return 1;
3362     }
3363    
3364            break;
3365        }
3366    
3367        return 0;
3368    }
3369    
3370    int updateInitrd(struct grubConfig * cfg, const char * image,
3371                     const char * prefix, const char * initrd, const char * title) {
3372        struct singleEntry * entry;
3373        struct singleLine * line, * kernelLine, *endLine = NULL;
3374        int index = 0;
3375    
3376        if (!image) return 0;
3377    
3378        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3379            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3380            if (!kernelLine) continue;
3381    
3382     /* if title is supplied, the entry's title must match it. */
3383     if (title) {
3384        char *linetitle;
3385    
3386        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3387        if (!line)
3388     continue;
3389    
3390        linetitle = extractTitle(line);
3391        if (!linetitle)
3392     continue;
3393        if (strcmp(title, linetitle)) {
3394     free(linetitle);
3395     continue;
3396        }
3397        free(linetitle);
3398     }
3399    
3400            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3401            if (line)
3402                removeLine(entry, line);
3403            if (prefix) {
3404                int prefixLen = strlen(prefix);
3405                if (!strncmp(initrd, prefix, prefixLen))
3406                    initrd += prefixLen;
3407            }
3408     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3409     if (endLine)
3410        removeLine(entry, endLine);
3411     enum lineType_e lt;
3412     switch(kernelLine->type) {
3413        case LT_KERNEL:
3414            lt = LT_INITRD;
3415     break;
3416        case LT_KERNEL_EFI:
3417            lt = LT_INITRD_EFI;
3418     break;
3419        case LT_KERNEL_16:
3420            lt = LT_INITRD_16;
3421     break;
3422        default:
3423            lt = preferredLineType(LT_INITRD, cfg->cfi);
3424     }
3425            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3426            if (!line)
3427        return 1;
3428     if (endLine) {
3429        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3430                if (!line)
3431     return 1;
3432     }
3433    
3434            break;
3435        }
3436    
3437        return 0;
3438    }
3439    
3440  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3441      int fd;      int fd;
3442      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3460  int checkDeviceBootloader(const char * d
3460      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3461   return 0;   return 0;
3462    
3463      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3464   offset = boot[2] + 2;   offset = boot[2] + 2;
3465      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3466   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3467      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3468   offset = boot[1] + 2;        offset = boot[1] + 2;
3469            /*
3470     * it looks like grub, when copying stage1 into the mbr, patches stage1
3471     * right after the JMP location, replacing other instructions such as
3472     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3473     * different bytes.
3474     */
3475          if ((bootSect[offset + 1] == NOOP_OPCODE)
3476      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3477     offset = offset + 3;
3478          }
3479      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3480   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3481      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3617  int checkForLilo(struct grubConfig * con
3617      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3618  }  }
3619    
3620    int checkForGrub2(struct grubConfig * config) {
3621        if (!access("/etc/grub.d/", R_OK))
3622     return 2;
3623    
3624        return 1;
3625    }
3626    
3627  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3628      int fd;      int fd;
3629      unsigned char bootSect[512];      unsigned char bootSect[512];
3630      char * boot;      char * boot;
3631        int onSuse = isSuseSystem();
3632    
3633      if (parseSysconfigGrub(NULL, &boot))  
3634   return 0;      if (onSuse) {
3635     if (parseSuseGrubConf(NULL, &boot))
3636        return 0;
3637        } else {
3638     if (parseSysconfigGrub(NULL, &boot))
3639        return 0;
3640        }
3641    
3642      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3643      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3651  int checkForGrub(struct grubConfig * con
3651      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3652   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3653   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3654     close(fd);
3655     return 1;
3656        }
3657        close(fd);
3658    
3659        /* The more elaborate checks do not work on SuSE. The checks done
3660         * seem to be reasonble (at least for now), so just return success
3661         */
3662        if (onSuse)
3663     return 2;
3664    
3665        return checkDeviceBootloader(boot, bootSect);
3666    }
3667    
3668    int checkForExtLinux(struct grubConfig * config) {
3669        int fd;
3670        unsigned char bootSect[512];
3671        char * boot;
3672        char executable[] = "/boot/extlinux/extlinux";
3673    
3674        printf("entered: checkForExtLinux()\n");
3675    
3676        if (parseSysconfigGrub(NULL, &boot))
3677     return 0;
3678    
3679        /* assume grub is not installed -- not an error condition */
3680        if (!boot)
3681     return 0;
3682    
3683        fd = open(executable, O_RDONLY);
3684        if (fd < 0)
3685     /* this doesn't exist if grub hasn't been installed */
3686     return 0;
3687    
3688        if (read(fd, bootSect, 512) != 512) {
3689     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3690     executable, strerror(errno));
3691   return 1;   return 1;
3692      }      }
3693      close(fd);      close(fd);
# Line 1983  int checkForGrub(struct grubConfig * con Line 3695  int checkForGrub(struct grubConfig * con
3695      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3696  }  }
3697    
3698    int checkForYaboot(struct grubConfig * config) {
3699        /*
3700         * This is a simplistic check that we consider good enough for own puporses
3701         *
3702         * If we were to properly check if yaboot is *installed* we'd need to:
3703         * 1) get the system boot device (LT_BOOT)
3704         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3705         *    the content on the boot device
3706         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3707         * 4) check again if binary and boot device contents match
3708         */
3709        if (!access("/etc/yaboot.conf", R_OK))
3710     return 2;
3711    
3712        return 1;
3713    }
3714    
3715    int checkForElilo(struct grubConfig * config) {
3716        if (!access("/etc/elilo.conf", R_OK))
3717     return 2;
3718    
3719        return 1;
3720    }
3721    
3722  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3723      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3724    
# Line 1994  static char * getRootSpecifier(char * st Line 3730  static char * getRootSpecifier(char * st
3730      return rootspec;      return rootspec;
3731  }  }
3732    
3733    static char * getInitrdVal(struct grubConfig * config,
3734       const char * prefix, struct singleLine *tmplLine,
3735       const char * newKernelInitrd,
3736       const char ** extraInitrds, int extraInitrdCount)
3737    {
3738        char *initrdVal, *end;
3739        int i;
3740        size_t totalSize;
3741        size_t prefixLen;
3742        char separatorChar;
3743    
3744        prefixLen = strlen(prefix);
3745        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3746    
3747        for (i = 0; i < extraInitrdCount; i++) {
3748     totalSize += sizeof(separatorChar);
3749     totalSize += strlen(extraInitrds[i]) - prefixLen;
3750        }
3751    
3752        initrdVal = end = malloc(totalSize);
3753    
3754        end = stpcpy (end, newKernelInitrd + prefixLen);
3755    
3756        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3757        for (i = 0; i < extraInitrdCount; i++) {
3758     const char *extraInitrd;
3759     int j;
3760    
3761     extraInitrd = extraInitrds[i] + prefixLen;
3762     /* Don't add entries that are already there */
3763     if (tmplLine != NULL) {
3764        for (j = 2; j < tmplLine->numElements; j++)
3765     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3766        break;
3767    
3768        if (j != tmplLine->numElements)
3769     continue;
3770     }
3771    
3772     *end++ = separatorChar;
3773     end = stpcpy(end, extraInitrd);
3774        }
3775    
3776        return initrdVal;
3777    }
3778    
3779  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3780           const char * prefix,           const char * prefix,
3781   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3782   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3783                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3784                     const char * newMBKernel, const char * newMBKernelArgs,
3785     const char * newDevTreePath) {
3786      struct singleEntry * new;      struct singleEntry * new;
3787      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3788      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3789      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3790    
3791      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3792    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3816  int addNewKernel(struct grubConfig * con
3816      config->entries = new;      config->entries = new;
3817    
3818      /* copy/update from the template */      /* copy/update from the template */
3819      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3820        if (newKernelInitrd)
3821     needs |= NEED_INITRD;
3822      if (newMBKernel) {      if (newMBKernel) {
3823          needs |= KERNEL_MB;          needs |= NEED_MB;
3824          new->multiboot = 1;          new->multiboot = 1;
3825      }      }
3826        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3827     needs |= NEED_DEVTREE;
3828    
3829      if (template) {      if (template) {
3830   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3831      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3832      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3833   indent = tmplLine->indent;   {
3834        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3835    
3836      /* skip comments */      /* skip comments */
3837      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3838      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3839      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3840    
3841      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3842      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3843        /* it's not a multiboot template and this is the kernel
3844              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3845                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3846                  struct singleLine *l;       */
3847                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3848     /* insert the hypervisor first */
3849                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3850                                    config->secondaryIndent,    tmplLine->indent,
3851                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3852                     /* set up for adding the kernel line */
3853                  tmplLine = lastLine;   free(tmplLine->indent);
3854                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3855                      new->lines = l;   needs &= ~NEED_MB;
3856                  } else {      }
3857                      newLine->next = l;      if (needs & NEED_KERNEL) {
3858                      newLine = l;   /* use addLineTmpl to preserve line elements,
3859                  }   * otherwise we could just call addLine.  Unfortunately
3860                  continue;   * this means making some changes to the template
3861              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3862                         template->multiboot && !new->multiboot) {   * change below.
3863                  continue; /* don't need multiboot kernel here */   */
3864              }   struct keywordTypes * mbm_kw =
3865        getKeywordByType(LT_MBMODULE, config->cfi);
3866      if (!new->lines) {   if (mbm_kw) {
3867   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3868   new->lines = newLine;      free(tmplLine->elements[0].item);
3869      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3870   newLine->next = malloc(sizeof(*newLine));   }
3871   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3872      }        newKernelPath + strlen(prefix), config->cfi);
3873     needs &= ~NEED_KERNEL;
3874        }
3875        if (needs & NEED_MB) { /* !mbHyperFirst */
3876     newLine = addLine(new, config->cfi, LT_HYPER,
3877      config->secondaryIndent,
3878      newMBKernel + strlen(prefix));
3879     needs &= ~NEED_MB;
3880        }
3881     } else if (needs & NEED_KERNEL) {
3882        newLine = addLineTmpl(new, tmplLine, newLine,
3883      newKernelPath + strlen(prefix), config->cfi);
3884        needs &= ~NEED_KERNEL;
3885     }
3886    
3887        } else if (tmplLine->type == LT_HYPER &&
3888           tmplLine->numElements >= 2) {
3889     if (needs & NEED_MB) {
3890        newLine = addLineTmpl(new, tmplLine, newLine,
3891      newMBKernel + strlen(prefix), config->cfi);
3892        needs &= ~NEED_MB;
3893     }
3894    
3895      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3896      newLine->next = NULL;         tmplLine->numElements >= 2) {
3897      newLine->type = tmplLine->type;   if (new->multiboot) {
3898      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3899      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3900      newLine->numElements);        newKernelPath +
3901      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3902   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3903   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3904   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3905      }   char *initrdVal;
3906     initrdVal = getInitrdVal(config, prefix, tmplLine,
3907              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3908      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3909                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3910                  if (!template->multiboot) {        initrdVal, config->cfi);
3911                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3912                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3913                  } else {      }
3914                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3915                      repl = newMBKernel;      /* template is multi but new is not,
3916                  }       * insert the kernel in the first module slot
3917                  if (new->multiboot && !template->multiboot) {       */
3918                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3919                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3920                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3921                  }   strdup(getKeywordByType(tmplLine->type,
3922   free(newLine->elements[1].item);   config->cfi)->key);
3923                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3924                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3925                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3926                                                             rootspec,      needs &= ~NEED_KERNEL;
3927                                                             repl +   } else if (needs & NEED_INITRD) {
3928                                                             strlen(prefix));      char *initrdVal;
3929                  } else {      /* template is multi but new is not,
3930                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3931                                                         strlen(prefix));       */
3932                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3933              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3934                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3935                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3936                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3937                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3938                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3939                      newLine->type = LT_KERNEL;      free(initrdVal);
3940                  }      needs &= ~NEED_INITRD;
3941   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;  
3942    
3943   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3944      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3945      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3946        config->cfi->mbInitRdIsModule) {
3947        /* make sure we don't insert the module initrd
3948         * before the module kernel... if we don't do it here,
3949         * it will be inserted following the template.
3950         */
3951        if (!needs & NEED_KERNEL) {
3952     char *initrdVal;
3953    
3954     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3955     newLine = addLine(new, config->cfi, LT_MBMODULE,
3956      config->secondaryIndent,
3957      initrdVal);
3958     free(initrdVal);
3959     needs &= ~NEED_INITRD;
3960        }
3961     } else if (needs & NEED_INITRD) {
3962        char *initrdVal;
3963        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3964        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3965        free(initrdVal);
3966        needs &= ~NEED_INITRD;
3967   }   }
3968    
3969   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3970   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3971   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3972     char *nkt = malloc(strlen(newKernelTitle)+3);
3973     strcpy(nkt, "'");
3974     strcat(nkt, newKernelTitle);
3975     strcat(nkt, "'");
3976     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3977     free(nkt);
3978     needs &= ~NEED_TITLE;
3979      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3980                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3981                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3982                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3983                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3984                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3985                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3986                                             newLine->numElements);     config->cfi->titleBracketed) {
3987        /* addLineTmpl doesn't handle titleBracketed */
3988                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3989                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3990                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3991                  newLine->numElements = 1;   }
3992              }      } else if (tmplLine->type == LT_ECHO) {
3993        requote(tmplLine, config->cfi);
3994        static const char *prefix = "'Loading ";
3995        if (tmplLine->numElements > 1 &&
3996        strstr(tmplLine->elements[1].item, prefix) &&
3997        masterLine->next &&
3998        iskernel(masterLine->next->type)) {
3999     char *newTitle = malloc(strlen(prefix) +
4000     strlen(newKernelTitle) + 2);
4001    
4002     strcpy(newTitle, prefix);
4003     strcat(newTitle, newKernelTitle);
4004     strcat(newTitle, "'");
4005     newLine = addLine(new, config->cfi, LT_ECHO,
4006     tmplLine->indent, newTitle);
4007     free(newTitle);
4008        } else {
4009     /* pass through other lines from the template */
4010     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
4011     config->cfi);
4012        }
4013        } else if (tmplLine->type == LT_DEVTREE &&
4014           tmplLine->numElements == 2 && newDevTreePath) {
4015            newLine = addLineTmpl(new, tmplLine, newLine,
4016          newDevTreePath + strlen(prefix),
4017          config->cfi);
4018     needs &= ~NEED_DEVTREE;
4019        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
4020     const char *ndtp = newDevTreePath;
4021     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
4022        ndtp += strlen(prefix);
4023     newLine = addLine(new, config->cfi, LT_DEVTREE,
4024      config->secondaryIndent,
4025      ndtp);
4026     needs &= ~NEED_DEVTREE;
4027     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4028        } else {
4029     /* pass through other lines from the template */
4030     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4031        }
4032   }   }
4033    
4034      } else {      } else {
4035   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
4036      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
4037     */
4038     switch (config->cfi->entryStart) {
4039        case LT_KERNEL:
4040        case LT_KERNEL_EFI:
4041        case LT_KERNEL_16:
4042     if (new->multiboot && config->cfi->mbHyperFirst) {
4043        /* fall through to LT_HYPER */
4044     } else {
4045        newLine = addLine(new, config->cfi,
4046              preferredLineType(LT_KERNEL, config->cfi),
4047          config->primaryIndent,
4048          newKernelPath + strlen(prefix));
4049        needs &= ~NEED_KERNEL;
4050        break;
4051     }
4052    
4053        case LT_HYPER:
4054     newLine = addLine(new, config->cfi, LT_HYPER,
4055      config->primaryIndent,
4056      newMBKernel + strlen(prefix));
4057     needs &= ~NEED_MB;
4058   break;   break;
         }  
4059    
4060   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
4061      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
4062       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
4063       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
4064      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
4065       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
4066      default:        config->primaryIndent, nkt);
4067                  /* zipl strikes again */   free(nkt);
4068                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
4069                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
4070                      chptr = newKernelTitle;   break;
4071                      type = LT_TITLE;      }
4072                      break;      case LT_TITLE:
4073                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
4074                      abort();   char * templabel;
4075                  }   int x = 0, y = 0;
4076   }  
4077     templabel = strdup(newKernelTitle);
4078     while( templabel[x]){
4079     if( templabel[x] == ' ' ){
4080     y = x;
4081     while( templabel[y] ){
4082     templabel[y] = templabel[y+1];
4083     y++;
4084     }
4085     }
4086     x++;
4087     }
4088     newLine = addLine(new, config->cfi, LT_TITLE,
4089      config->primaryIndent, templabel);
4090     free(templabel);
4091     }else{
4092     newLine = addLine(new, config->cfi, LT_TITLE,
4093      config->primaryIndent, newKernelTitle);
4094     }
4095     needs &= ~NEED_TITLE;
4096     break;
4097    
4098   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
4099   new->lines = newLine;   abort();
4100     }
4101      }      }
4102    
4103      if (new->multiboot) {      struct singleLine *endLine = NULL;
4104          if (needs & KERNEL_MB)      endLine = getLineByType(LT_ENTRY_END, new->lines);
4105              newLine = addLine(new, config->cfi, LT_KERNEL,      if (endLine) {
4106                                config->secondaryIndent,      removeLine(new, endLine);
4107                                newMBKernel + strlen(prefix));      needs |= NEED_END;
4108          if (needs & KERNEL_KERNEL)      }
4109              newLine = addLine(new, config->cfi, LT_MBMODULE,  
4110                                config->secondaryIndent,      /* add the remainder of the lines, i.e. those that either
4111                                newKernelPath + strlen(prefix));       * weren't present in the template, or in the case of no template,
4112          /* don't need to check for title as it's guaranteed to have been       * all the lines following the entryStart.
4113           * done as we only do multiboot with grub which uses title as       */
4114           * a separator */      if (needs & NEED_TITLE) {
4115          if (needs & KERNEL_INITRD && newKernelInitrd)   newLine = addLine(new, config->cfi, LT_TITLE,
4116              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
4117                                config->secondaryIndent,    newKernelTitle);
4118                                newKernelInitrd + strlen(prefix));   needs &= ~NEED_TITLE;
4119      } else {      }
4120          if (needs & KERNEL_KERNEL)      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
4121              newLine = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
4122                                config->secondaryIndent,    config->secondaryIndent,
4123                                newKernelPath + strlen(prefix));    newMBKernel + strlen(prefix));
4124          if (needs & KERNEL_TITLE)   needs &= ~NEED_MB;
4125              newLine = addLine(new, config->cfi, LT_TITLE,      }
4126                                config->secondaryIndent,      if (needs & NEED_KERNEL) {
4127                                newKernelTitle);   newLine = addLine(new, config->cfi,
4128          if (needs & KERNEL_INITRD && newKernelInitrd)    (new->multiboot && getKeywordByType(LT_MBMODULE,
4129              newLine = addLine(new, config->cfi, LT_INITRD,        config->cfi))
4130                                config->secondaryIndent,     ? LT_MBMODULE
4131                                newKernelInitrd + strlen(prefix));   : preferredLineType(LT_KERNEL, config->cfi),
4132      config->secondaryIndent,
4133      newKernelPath + strlen(prefix));
4134     needs &= ~NEED_KERNEL;
4135        }
4136        if (needs & NEED_MB) {
4137     newLine = addLine(new, config->cfi, LT_HYPER,
4138      config->secondaryIndent,
4139      newMBKernel + strlen(prefix));
4140     needs &= ~NEED_MB;
4141        }
4142        if (needs & NEED_INITRD) {
4143     char *initrdVal;
4144     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4145     newLine = addLine(new, config->cfi,
4146      (new->multiboot && getKeywordByType(LT_MBMODULE,
4147          config->cfi))
4148       ? LT_MBMODULE
4149       : preferredLineType(LT_INITRD, config->cfi),
4150      config->secondaryIndent,
4151      initrdVal);
4152     free(initrdVal);
4153     needs &= ~NEED_INITRD;
4154        }
4155        if (needs & NEED_DEVTREE) {
4156     newLine = addLine(new, config->cfi, LT_DEVTREE,
4157      config->secondaryIndent,
4158      newDevTreePath);
4159     needs &= ~NEED_DEVTREE;
4160        }
4161    
4162        /* NEEDS_END must be last on bootloaders that need it... */
4163        if (needs & NEED_END) {
4164     newLine = addLine(new, config->cfi, LT_ENTRY_END,
4165     config->secondaryIndent, NULL);
4166     needs &= ~NEED_END;
4167        }
4168    
4169        if (needs) {
4170     printf(_("grubby: needs=%d, aborting\n"), needs);
4171     abort();
4172      }      }
4173    
4174      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 4177  int addNewKernel(struct grubConfig * con
4177      return 0;      return 0;
4178  }  }
4179    
4180    static void traceback(int signum)
4181    {
4182        void *array[40];
4183        size_t size;
4184    
4185        signal(SIGSEGV, SIG_DFL);
4186        memset(array, '\0', sizeof (array));
4187        size = backtrace(array, 40);
4188    
4189        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4190                (unsigned long)size);
4191        backtrace_symbols_fd(array, size, STDERR_FILENO);
4192        exit(1);
4193    }
4194    
4195  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4196      poptContext optCon;      poptContext optCon;
4197      char * grubConfig = NULL;      const char * grubConfig = NULL;
4198      char * outputFile = NULL;      char * outputFile = NULL;
4199      int arg = 0;      int arg = 0;
4200      int flags = 0;      int flags = 0;
4201      int badImageOkay = 0;      int badImageOkay = 0;
4202        int configureGrub2 = 0;
4203      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4204      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4205        int configureExtLinux = 0;
4206      int bootloaderProbe = 0;      int bootloaderProbe = 0;
4207        int extraInitrdCount = 0;
4208      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
4209      char * newKernelPath = NULL;      char * newKernelPath = NULL;
4210      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
4211      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4212      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4213      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4214      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4215      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4216      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4217      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 4220  int main(int argc, const char ** argv) {
4220      char * defaultKernel = NULL;      char * defaultKernel = NULL;
4221      char * removeArgs = NULL;      char * removeArgs = NULL;
4222      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4223        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4224        char * envPath = NULL;
4225      const char * chptr = NULL;      const char * chptr = NULL;
4226      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4227      struct grubConfig * config;      struct grubConfig * config;
4228      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4229      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4230      int displayDefault = 0;      int displayDefault = 0;
4231        int displayDefaultIndex = 0;
4232        int displayDefaultTitle = 0;
4233        int defaultIndex = -1;
4234      struct poptOption options[] = {      struct poptOption options[] = {
4235   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4236      _("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 4248  int main(int argc, const char ** argv) {
4248   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4249      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4250      _("bootfs") },      _("bootfs") },
4251  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4252   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4253      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4254  #endif  #endif
4255   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4256      _("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 4261  int main(int argc, const char ** argv) {
4261        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4262        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4263        "template"), NULL },        "template"), NULL },
4264     { "debug", 0, 0, &debug, 0,
4265        _("print debugging information for failures") },
4266   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4267      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4268     { "default-index", 0, 0, &displayDefaultIndex, 0,
4269        _("display the index of the default kernel") },
4270     { "default-title", 0, 0, &displayDefaultTitle, 0,
4271        _("display the title of the default kernel") },
4272     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4273        _("device tree file for new stanza"), _("dtb-path") },
4274     { "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4275        _("device tree directory for new stanza"), _("dtb-path") },
4276   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4277      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4278     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4279        _("force grub2 stanzas to use efi") },
4280     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4281        _("path for environment data"),
4282        _("path") },
4283     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4284        _("configure extlinux bootloader (from syslinux)") },
4285   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4286      _("configure grub bootloader") },      _("configure grub bootloader") },
4287     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4288        _("configure grub2 bootloader") },
4289   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4290      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4291      _("kernel-path") },      _("kernel-path") },
4292   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4293      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4294     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4295        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4296   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4297      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4298   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4312  int main(int argc, const char ** argv) {
4312   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4313      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4314        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4315     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4316        _("make the given entry index the default entry"),
4317        _("entry-index") },
4318   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4319      _("configure silo bootloader") },      _("configure silo bootloader") },
4320   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4332  int main(int argc, const char ** argv) {
4332   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4333      };      };
4334    
4335        useextlinuxmenu=0;
4336    
4337        signal(SIGSEGV, traceback);
4338    
4339        int i = 0;
4340        for (int j = 1; j < argc; j++)
4341     i += strlen(argv[j]) + 1;
4342        saved_command_line = malloc(i);
4343        if (!saved_command_line) {
4344     fprintf(stderr, "grubby: %m\n");
4345     exit(1);
4346        }
4347        saved_command_line[0] = '\0';
4348        for (int j = 1; j < argc; j++) {
4349     strcat(saved_command_line, argv[j]);
4350     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4351        }
4352    
4353      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4354      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4355    
# Line 2391  int main(int argc, const char ** argv) { Line 4359  int main(int argc, const char ** argv) {
4359      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4360      exit(0);      exit(0);
4361      break;      break;
4362      case 'i':
4363        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4364         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4365        } else {
4366     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4367     return 1;
4368        }
4369        break;
4370   }   }
4371      }      }
4372    
# Line 2406  int main(int argc, const char ** argv) { Line 4382  int main(int argc, const char ** argv) {
4382   return 1;   return 1;
4383      }      }
4384    
4385      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4386   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4387     configureExtLinux ) > 1) {
4388   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4389   return 1;   return 1;
4390      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4391   fprintf(stderr,   fprintf(stderr,
4392      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4393   return 1;   return 1;
4394        } else if (configureGrub2) {
4395     cfi = &grub2ConfigType;
4396     if (envPath)
4397        cfi->envFile = envPath;
4398      } else if (configureLilo) {      } else if (configureLilo) {
4399   cfi = &liloConfigType;   cfi = &liloConfigType;
4400      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4407  int main(int argc, const char ** argv) {
4407          cfi = &siloConfigType;          cfi = &siloConfigType;
4408      } else if (configureZipl) {      } else if (configureZipl) {
4409          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4410        } else if (configureExtLinux) {
4411     cfi = &extlinuxConfigType;
4412     useextlinuxmenu=1;
4413      }      }
4414    
4415      if (!cfi) {      if (!cfi) {
4416            if (grub2FindConfig(&grub2ConfigType))
4417        cfi = &grub2ConfigType;
4418     else
4419        #ifdef __ia64__        #ifdef __ia64__
4420   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4421        #elif __powerpc__        #elif __powerpc__
4422   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4423        #elif __sparc__        #elif __sparc__
4424          cfi = &siloConfigType;              cfi = &siloConfigType;
4425        #elif __s390__        #elif __s390__
4426          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4427        #elif __s390x__        #elif __s390x__
4428          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4429        #else        #else
4430   cfi = &grubConfigType;      cfi = &grubConfigType;
4431        #endif        #endif
4432      }      }
4433    
4434      if (!grubConfig)      if (!grubConfig) {
4435   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4436        grubConfig = cfi->findConfig(cfi);
4437     if (!grubConfig)
4438        grubConfig = cfi->defaultConfig;
4439        }
4440    
4441      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4442    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4443    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4444        (defaultIndex >= 0))) {
4445   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4446    "specified option"));    "specified option"));
4447   return 1;   return 1;
4448      }      }
4449    
4450      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4451     removeKernelPath)) {     removeKernelPath)) {
4452   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4453    "be used when adding or removing kernels\n"));    "be used when adding or removing kernels\n"));
# Line 2465  int main(int argc, const char ** argv) { Line 4457  int main(int argc, const char ** argv) {
4457      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4458   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4459   return 1;   return 1;
4460      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (copyDefault ||
4461    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4462    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4463   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4464   return 1;   return 1;
4465      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4483  int main(int argc, const char ** argv) {
4483   makeDefault = 1;   makeDefault = 1;
4484   defaultKernel = NULL;   defaultKernel = NULL;
4485      }      }
4486        else if (defaultKernel && (defaultIndex >= 0)) {
4487     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4488      "may not be used together\n"));
4489     return 1;
4490        }
4491    
4492      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4493   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4494   "is used\n"));   "is used\n"));
4495   return 1;   return 1;
4496      }      }
4497    
4498      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4499   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4500          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4501     && (defaultIndex == -1)) {
4502   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4503   return 1;   return 1;
4504      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4518  int main(int argc, const char ** argv) {
4518   bootPrefix = "";   bootPrefix = "";
4519      }      }
4520    
4521        if (!cfi->mbAllowExtraInitRds &&
4522     extraInitrdCount > 0) {
4523     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4524     return 1;
4525        }
4526    
4527      if (bootloaderProbe) {      if (bootloaderProbe) {
4528   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4529   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4530    
4531     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4532     if (grub2config) {
4533        gconfig = readConfig(grub2config, &grub2ConfigType);
4534        if (!gconfig)
4535     gr2c = 1;
4536        else
4537     gr2c = checkForGrub2(gconfig);
4538     }
4539    
4540   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4541      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4542        gconfig = readConfig(grubconfig, &grubConfigType);
4543      if (!gconfig)      if (!gconfig)
4544   grc = 1;   grc = 1;
4545      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4554  int main(int argc, const char ** argv) {
4554   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4555   }   }
4556    
4557   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4558        econfig = readConfig(eliloConfigType.defaultConfig,
4559     &eliloConfigType);
4560        if (!econfig)
4561     erc = 1;
4562        else
4563     erc = checkForElilo(econfig);
4564     }
4565    
4566     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4567        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4568        if (!lconfig)
4569     extrc = 1;
4570        else
4571     extrc = checkForExtLinux(lconfig);
4572     }
4573    
4574    
4575     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4576        yconfig = readConfig(yabootConfigType.defaultConfig,
4577     &yabootConfigType);
4578        if (!yconfig)
4579     yrc = 1;
4580        else
4581     yrc = checkForYaboot(yconfig);
4582     }
4583    
4584     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4585     erc == 1)
4586        return 1;
4587    
4588   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4589     if (gr2c == 2) printf("grub2\n");
4590   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4591     if (extrc == 2) printf("extlinux\n");
4592     if (yrc == 2) printf("yaboot\n");
4593     if (erc == 2) printf("elilo\n");
4594    
4595   return 0;   return 0;
4596      }      }
4597    
4598        if (grubConfig == NULL) {
4599     printf("Could not find bootloader configuration file.\n");
4600     exit(1);
4601        }
4602    
4603      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4604      if (!config) return 1;      if (!config) return 1;
4605    
# Line 2557  int main(int argc, const char ** argv) { Line 4609  int main(int argc, const char ** argv) {
4609          char * rootspec;          char * rootspec;
4610    
4611   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4612     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4613     cfi->defaultIsSaved)
4614        config->defaultImage = 0;
4615   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4616   if (!entry) return 0;   if (!entry) return 0;
4617   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4618    
4619   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;  
4620   if (!line) return 0;   if (!line) return 0;
4621    
4622          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4624  int main(int argc, const char ** argv) {
4624                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4625    
4626   return 0;   return 0;
4627    
4628        } else if (displayDefaultTitle) {
4629     struct singleLine * line;
4630     struct singleEntry * entry;
4631    
4632     if (config->defaultImage == -1) return 0;
4633     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4634     cfi->defaultIsSaved)
4635        config->defaultImage = 0;
4636     entry = findEntryByIndex(config, config->defaultImage);
4637     if (!entry) return 0;
4638    
4639     if (!configureGrub2) {
4640      line = getLineByType(LT_TITLE, entry->lines);
4641      if (!line) return 0;
4642      printf("%s\n", line->elements[1].item);
4643    
4644     } else {
4645      char * title;
4646    
4647      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4648      line = getLineByType(LT_MENUENTRY, entry->lines);
4649      if (!line) return 0;
4650      title = grub2ExtractTitle(line);
4651      if (title)
4652        printf("%s\n", title);
4653     }
4654     return 0;
4655    
4656        } else if (displayDefaultIndex) {
4657            if (config->defaultImage == -1) return 0;
4658     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4659     cfi->defaultIsSaved)
4660        config->defaultImage = 0;
4661            printf("%i\n", config->defaultImage);
4662            return 0;
4663    
4664      } else if (kernelInfo)      } else if (kernelInfo)
4665   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4666    
# Line 2581  int main(int argc, const char ** argv) { Line 4672  int main(int argc, const char ** argv) {
4672      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4673      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4674      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4675      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4676      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4677      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4678                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4679        if (updateKernelPath && newKernelInitrd) {
4680        if (newMBKernel) {
4681        if (addMBInitrd(config, newMBKernel, updateKernelPath,
4682     bootPrefix, newKernelInitrd,
4683     newKernelTitle))
4684        return 1;
4685        } else {
4686        if (updateInitrd(config, updateKernelPath, bootPrefix,
4687     newKernelInitrd, newKernelTitle))
4688     return 1;
4689        }
4690        }
4691      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4692                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4693                       newMBKernel, newMBKernelArgs)) return 1;                       (const char **)extraInitrds, extraInitrdCount,
4694                         newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4695            
4696    
4697      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {
# Line 2597  int main(int argc, const char ** argv) { Line 4701  int main(int argc, const char ** argv) {
4701      }      }
4702    
4703      if (!outputFile)      if (!outputFile)
4704   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4705    
4706      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4707  }  }

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