Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 2687 by niro, Wed Jul 16 10:41:38 2014 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39    #include "log.h"
40    
41    #ifndef DEBUG
42    #define DEBUG 0
43    #endif
44    
45    #if DEBUG
46    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
47    #else
48    #define dbgPrintf(format, args...)
49    #endif
50    
51  #include "mount_by_label.h"  int debug = 0; /* Currently just for template debugging */
52    
53  #define _(A) (A)  #define _(A) (A)
54    
55    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
56  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
57    
58    #define NOOP_OPCODE 0x90
59    #define JMP_SHORT_OPCODE 0xeb
60    
61    int isEfi = 0;
62    
63    char *saved_command_line = NULL;
64    
65  /* comments get lumped in with indention */  /* comments get lumped in with indention */
66  struct lineElement {  struct lineElement {
67      char * item;      char * item;
68      char * indent;      char * indent;
69  };  };
70    
71  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
72         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
73         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
74        LT_KERNEL       = 1 << 2,
75        LT_INITRD       = 1 << 3,
76        LT_HYPER        = 1 << 4,
77        LT_DEFAULT      = 1 << 5,
78        LT_MBMODULE     = 1 << 6,
79        LT_ROOT         = 1 << 7,
80        LT_FALLBACK     = 1 << 8,
81        LT_KERNELARGS   = 1 << 9,
82        LT_BOOT         = 1 << 10,
83        LT_BOOTROOT     = 1 << 11,
84        LT_LBA          = 1 << 12,
85        LT_OTHER        = 1 << 13,
86        LT_GENERIC      = 1 << 14,
87        LT_ECHO    = 1 << 16,
88        LT_MENUENTRY    = 1 << 17,
89        LT_ENTRY_END    = 1 << 18,
90        LT_SET_VARIABLE = 1 << 19,
91        LT_KERNEL_EFI   = 1 << 20,
92        LT_INITRD_EFI   = 1 << 21,
93        LT_KERNEL_16    = 1 << 22,
94        LT_INITRD_16    = 1 << 23,
95        LT_DEVTREE      = 1 << 24,
96        LT_UNKNOWN      = 1 << 25,
97    };
98    
99  struct singleLine {  struct singleLine {
100      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 115  struct singleEntry {
115    
116  #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 */
117    
118  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
119  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
120  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
121  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
122  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
123    #define NEED_MB      (1 << 4)
124    #define NEED_END     (1 << 5)
125    #define NEED_DEVTREE (1 << 6)
126    
127  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
128  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
129    #define DEFAULT_SAVED_GRUB2 -3
130    
131  struct keywordTypes {  struct keywordTypes {
132      char * key;      char * key;
133      enum lineType_e type;      enum lineType_e type;
134      char nextChar;      char nextChar;
135  } ;      char separatorChar;
136    };
137    
138    struct configFileInfo;
139    
140    typedef const char *(*findConfigFunc)(struct configFileInfo *);
141    typedef const int (*writeLineFunc)(struct configFileInfo *,
142     struct singleLine *line);
143    typedef char *(*getEnvFunc)(struct configFileInfo *, char *name);
144    typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value);
145    
146  struct configFileInfo {  struct configFileInfo {
147      char * defaultConfig;      char * defaultConfig;
148        findConfigFunc findConfig;
149        writeLineFunc writeLine;
150        getEnvFunc getEnv;
151        setEnvFunc setEnv;
152      struct keywordTypes * keywords;      struct keywordTypes * keywords;
153        int caseInsensitive;
154      int defaultIsIndex;      int defaultIsIndex;
155        int defaultIsVariable;
156      int defaultSupportSaved;      int defaultSupportSaved;
157      enum lineType_e entrySeparator;      int defaultIsSaved;
158        enum lineType_e entryStart;
159        enum lineType_e entryEnd;
160      int needsBootPrefix;      int needsBootPrefix;
161      int argsInQuotes;      int argsInQuotes;
162      int maxTitleLength;      int maxTitleLength;
163      int titleBracketed;      int titleBracketed;
164        int titlePosition;
165        int mbHyperFirst;
166        int mbInitRdIsModule;
167        int mbConcatArgs;
168        int mbAllowExtraInitRds;
169        char *envFile;
170  };  };
171    
172  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 175  struct keywordTypes grubKeywords[] = {
175      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
176      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
177      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
178      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
179      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
180        { "kernel",     LT_HYPER,       ' ' },
181      { NULL,    0, 0 },      { NULL,    0, 0 },
182  };  };
183    
184    const char *grubFindConfig(struct configFileInfo *cfi) {
185        static const char *configFiles[] = {
186     "/boot/grub/grub.conf",
187     "/boot/grub/menu.lst",
188     "/etc/grub.conf",
189     "/boot/grub2/grub.cfg",
190     "/boot/grub2-efi/grub.cfg",
191     NULL
192        };
193        static int i = -1;
194    
195        if (i == -1) {
196     for (i = 0; configFiles[i] != NULL; i++) {
197        dbgPrintf("Checking \"%s\": ", configFiles[i]);
198        if (!access(configFiles[i], R_OK)) {
199     dbgPrintf("found\n");
200     return configFiles[i];
201        }
202        dbgPrintf("not found\n");
203     }
204        }
205        return configFiles[i];
206    }
207    
208  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
209      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
210      grubKeywords,    /* keywords */      .keywords = grubKeywords,
211      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
212      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
213      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
214      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
215      0,    /* argsInQuotes */      .mbHyperFirst = 1,
216      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
217      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
218    };
219    
220    struct keywordTypes grub2Keywords[] = {
221        { "menuentry",  LT_MENUENTRY,   ' ' },
222        { "}",          LT_ENTRY_END,   ' ' },
223        { "echo",       LT_ECHO,        ' ' },
224        { "set",        LT_SET_VARIABLE,' ', '=' },
225        { "root",       LT_BOOTROOT,    ' ' },
226        { "default",    LT_DEFAULT,     ' ' },
227        { "fallback",   LT_FALLBACK,    ' ' },
228        { "linux",      LT_KERNEL,      ' ' },
229        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
230        { "linux16",    LT_KERNEL_16,   ' ' },
231        { "initrd",     LT_INITRD,      ' ', ' ' },
232        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
233        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
234        { "module",     LT_MBMODULE,    ' ' },
235        { "kernel",     LT_HYPER,       ' ' },
236        { "devicetree", LT_DEVTREE,  ' ' },
237        { NULL, 0, 0 },
238    };
239    
240    const char *grub2FindConfig(struct configFileInfo *cfi) {
241        static const char *configFiles[] = {
242     "/boot/grub/grub-efi.cfg",
243     "/boot/grub/grub.cfg",
244     NULL
245        };
246        static int i = -1;
247        static const char *grub_cfg = "/boot/grub/grub.cfg";
248        int rc = -1;
249    
250        if (i == -1) {
251     for (i = 0; configFiles[i] != NULL; i++) {
252        dbgPrintf("Checking \"%s\": ", configFiles[i]);
253        if ((rc = access(configFiles[i], R_OK))) {
254     if (errno == EACCES) {
255        printf("Unable to access bootloader configuration file "
256           "\"%s\": %m\n", configFiles[i]);
257        exit(1);
258     }
259     continue;
260        } else {
261     dbgPrintf("found\n");
262     return configFiles[i];
263        }
264     }
265        }
266    
267        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
268         * that isn't in grub1, and if it exists, return the config file path
269         * that they use. */
270        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
271     dbgPrintf("found\n");
272     return grub_cfg;
273        }
274    
275        dbgPrintf("not found\n");
276        return configFiles[i];
277    }
278    
279    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
280    static char *grub2GetEnv(struct configFileInfo *info, char *name)
281    {
282        static char buf[1025];
283        char *s = NULL;
284        char *ret = NULL;
285        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
286        int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name);
287    
288        if (rc < 0)
289     return NULL;
290    
291        FILE *f = popen(s, "r");
292        if (!f)
293     goto out;
294    
295        memset(buf, '\0', sizeof (buf));
296        ret = fgets(buf, 1024, f);
297        pclose(f);
298    
299        if (ret) {
300     ret += strlen(name) + 1;
301     ret[strlen(ret) - 1] = '\0';
302        }
303        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
304    out:
305        free(s);
306        return ret;
307    }
308    
309    static int sPopCount(const char *s, const char *c)
310    {
311        int ret = 0;
312        if (!s)
313     return -1;
314        for (int i = 0; s[i] != '\0'; i++)
315     for (int j = 0; c[j] != '\0'; j++)
316        if (s[i] == c[j])
317     ret++;
318        return ret;
319    }
320    
321    static char *shellEscape(const char *s)
322    {
323        int l = strlen(s) + sPopCount(s, "'") * 2;
324    
325        char *ret = calloc(l+1, sizeof (*ret));
326        if (!ret)
327     return NULL;
328        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
329     if (s[i] == '\'')
330        ret[j++] = '\\';
331     ret[j] = s[i];
332        }
333        return ret;
334    }
335    
336    static void unquote(char *s)
337    {
338        int l = strlen(s);
339    
340        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
341     memmove(s, s+1, l-2);
342     s[l-2] = '\0';
343        }
344    }
345    
346    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
347    {
348        char *s = NULL;
349        int rc = 0;
350        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
351    
352        unquote(value);
353        value = shellEscape(value);
354        if (!value)
355        return -1;
356    
357        rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value);
358        free(value);
359        if (rc <0)
360     return -1;
361    
362        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
363        rc = system(s);
364        free(s);
365        return rc;
366    }
367    
368    /* this is a gigantic hack to avoid clobbering grub2 variables... */
369    static int is_special_grub2_variable(const char *name)
370    {
371        if (!strcmp(name,"\"${next_entry}\""))
372     return 1;
373        if (!strcmp(name,"\"${prev_saved_entry}\""))
374     return 1;
375        return 0;
376    }
377    
378    int sizeOfSingleLine(struct singleLine * line) {
379      int count = 0;
380    
381      for (int i = 0; i < line->numElements; i++) {
382        int indentSize = 0;
383    
384        count = count + strlen(line->elements[i].item);
385    
386        indentSize = strlen(line->elements[i].indent);
387        if (indentSize > 0)
388          count = count + indentSize;
389        else
390          /* be extra safe and add room for whitespaces */
391          count = count + 1;
392      }
393    
394      /* room for trailing terminator */
395      count = count + 1;
396    
397      return count;
398    }
399    
400    static int isquote(char q)
401    {
402        if (q == '\'' || q == '\"')
403     return 1;
404        return 0;
405    }
406    
407    static int iskernel(enum lineType_e type) {
408        return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
409    }
410    
411    static int isinitrd(enum lineType_e type) {
412        return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
413    }
414    
415    char *grub2ExtractTitle(struct singleLine * line) {
416        char * current;
417        char * current_indent;
418        int current_len;
419        int current_indent_len;
420        int i;
421    
422        /* bail out if line does not start with menuentry */
423        if (strcmp(line->elements[0].item, "menuentry"))
424          return NULL;
425    
426        i = 1;
427        current = line->elements[i].item;
428        current_len = strlen(current);
429    
430        /* if second word is quoted, strip the quotes and return single word */
431        if (isquote(*current) && isquote(current[current_len - 1])) {
432     char *tmp;
433    
434     tmp = strdup(current);
435     *(tmp + current_len - 1) = '\0';
436     return ++tmp;
437        }
438    
439        /* if no quotes, return second word verbatim */
440        if (!isquote(*current))
441     return current;
442    
443        /* second element start with a quote, so we have to find the element
444         * whose last character is also quote (assuming it's the closing one) */
445        int resultMaxSize;
446        char * result;
447        
448        resultMaxSize = sizeOfSingleLine(line);
449        result = malloc(resultMaxSize);
450        snprintf(result, resultMaxSize, "%s", ++current);
451        
452        i++;
453        for (; i < line->numElements; ++i) {
454     current = line->elements[i].item;
455     current_len = strlen(current);
456     current_indent = line->elements[i].indent;
457     current_indent_len = strlen(current_indent);
458    
459     strncat(result, current_indent, current_indent_len);
460     if (!isquote(current[current_len-1])) {
461        strncat(result, current, current_len);
462     } else {
463        strncat(result, current, current_len - 1);
464        break;
465     }
466        }
467        return result;
468    }
469    
470    struct configFileInfo grub2ConfigType = {
471        .findConfig = grub2FindConfig,
472        .getEnv = grub2GetEnv,
473        .setEnv = grub2SetEnv,
474        .keywords = grub2Keywords,
475        .defaultIsIndex = 1,
476        .defaultSupportSaved = 1,
477        .defaultIsVariable = 1,
478        .entryStart = LT_MENUENTRY,
479        .entryEnd = LT_ENTRY_END,
480        .titlePosition = 1,
481        .needsBootPrefix = 1,
482        .mbHyperFirst = 1,
483        .mbInitRdIsModule = 1,
484        .mbAllowExtraInitRds = 1,
485  };  };
486    
487  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 515  struct keywordTypes yabootKeywords[] = {
515      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
516      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
517      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
518      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
519      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
520      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
521      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 535  struct keywordTypes liloKeywords[] = {
535      { NULL,    0, 0 },      { NULL,    0, 0 },
536  };  };
537    
538    struct keywordTypes eliloKeywords[] = {
539        { "label",    LT_TITLE,    '=' },
540        { "root",    LT_ROOT,    '=' },
541        { "default",    LT_DEFAULT,    '=' },
542        { "image",    LT_KERNEL,    '=' },
543        { "initrd",    LT_INITRD,    '=' },
544        { "append",    LT_KERNELARGS,  '=' },
545        { "vmm",    LT_HYPER,       '=' },
546        { NULL,    0, 0 },
547    };
548    
549  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
550      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
551      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 567  struct keywordTypes ziplKeywords[] = {
567      { NULL,         0, 0 },      { NULL,         0, 0 },
568  };  };
569    
570    struct keywordTypes extlinuxKeywords[] = {
571        { "label",    LT_TITLE,    ' ' },
572        { "root",    LT_ROOT,    ' ' },
573        { "default",    LT_DEFAULT,    ' ' },
574        { "kernel",    LT_KERNEL,    ' ' },
575        { "initrd",    LT_INITRD,      ' ', ',' },
576        { "append",    LT_KERNELARGS,  ' ' },
577        { "prompt",     LT_UNKNOWN,     ' ' },
578        { NULL,    0, 0 },
579    };
580    int useextlinuxmenu;
581  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
582      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
583      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
584      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
585      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
586      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
587      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
588  };  };
589    
590  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
591      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
592      liloKeywords,    /* keywords */      .keywords = liloKeywords,
593      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
594      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
595      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
596  };  };
597    
598  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
599      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
600      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
601      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
602      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
603      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
604      1,    /* needsBootPrefix */      .maxTitleLength = 15,
605      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
606  };  };
607    
608  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
609      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
610      siloKeywords,    /* keywords */      .keywords = siloKeywords,
611      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
612      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
613      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
614      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
615  };  };
616    
617  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
618      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
619      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
620      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
621      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
622      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
623      0,    /* needsBootPrefix */  };
624      1,    /* argsInQuotes */  
625      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
626      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
627        .keywords = extlinuxKeywords,
628        .caseInsensitive = 1,
629        .entryStart = LT_TITLE,
630        .needsBootPrefix = 1,
631        .maxTitleLength = 255,
632        .mbAllowExtraInitRds = 1,
633  };  };
634    
635  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 644  struct grubConfig {
644      struct configFileInfo * cfi;      struct configFileInfo * cfi;
645  };  };
646    
647    blkid_cache blkid;
648    
649  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
650  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
651       const char * path, const char * prefix,       const char * path, const char * prefix,
652       int * index);       int * index);
653  static char * strndup(char * from, int len);  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
654          int * index);
655  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
656  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
657    struct singleLine * lineDup(struct singleLine * line);
658  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
659  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
660       struct configFileInfo * cfi);       struct configFileInfo * cfi);
661  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
662         struct configFileInfo * cfi);         struct configFileInfo * cfi);
663  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
664    static void requote(struct singleLine *line, struct configFileInfo * cfi);
665  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
666      char * to;    const char * item, int insertHere,
667      struct configFileInfo * cfi);
668      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
669      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
670      to[len] = '\0';        struct configFileInfo * cfi);
671    static enum lineType_e getTypeByKeyword(char * keyword,
672      return to;   struct configFileInfo * cfi);
673  }  static struct singleLine * getLineByType(enum lineType_e type,
674     struct singleLine * line);
675    static int checkForExtLinux(struct grubConfig * config);
676    struct singleLine * addLineTmpl(struct singleEntry * entry,
677                                    struct singleLine * tmplLine,
678                                    struct singleLine * prevLine,
679                                    const char * val,
680     struct configFileInfo * cfi);
681    struct singleLine *  addLine(struct singleEntry * entry,
682                                 struct configFileInfo * cfi,
683                                 enum lineType_e type, char * defaultIndent,
684                                 const char * val);
685    
686  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
687  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 716  static char * sdupprintf(const char *for
716      return buf;      return buf;
717  }  }
718    
719    static enum lineType_e preferredLineType(enum lineType_e type,
720     struct configFileInfo *cfi) {
721        if (isEfi && cfi == &grub2ConfigType) {
722     switch (type) {
723    #if defined(__aarch64__)
724     case LT_KERNEL:
725        return LT_KERNEL;
726     case LT_INITRD:
727        return LT_INITRD;
728    #else
729     case LT_KERNEL:
730        return LT_KERNEL_EFI;
731     case LT_INITRD:
732        return LT_INITRD_EFI;
733    #endif
734     default:
735        return type;
736     }
737    #if defined(__i386__) || defined(__x86_64__)
738        } else if (cfi == &grub2ConfigType) {
739     switch (type) {
740     case LT_KERNEL:
741        return LT_KERNEL_16;
742     case LT_INITRD:
743        return LT_INITRD_16;
744     default:
745        return type;
746     }
747    #endif
748        }
749        return type;
750    }
751    
752    static struct keywordTypes * getKeywordByType(enum lineType_e type,
753          struct configFileInfo * cfi) {
754        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
755     if (kw->type == type)
756        return kw;
757        }
758        return NULL;
759    }
760    
761    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
762        struct keywordTypes *kt = getKeywordByType(type, cfi);
763        if (kt)
764     return kt->key;
765        return "unknown";
766    }
767    
768    static char * getpathbyspec(char *device) {
769        if (!blkid)
770            blkid_get_cache(&blkid, NULL);
771    
772        return blkid_get_devname(blkid, device, NULL);
773    }
774    
775    static char * getuuidbydev(char *device) {
776        if (!blkid)
777     blkid_get_cache(&blkid, NULL);
778    
779        return blkid_get_tag_value(blkid, "UUID", device);
780    }
781    
782    static enum lineType_e getTypeByKeyword(char * keyword,
783     struct configFileInfo * cfi) {
784        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
785     if (cfi->caseInsensitive) {
786        if (!strcasecmp(keyword, kw->key))
787                    return kw->type;
788     } else {
789        if (!strcmp(keyword, kw->key))
790            return kw->type;
791     }
792        }
793        return LT_UNKNOWN;
794    }
795    
796    static struct singleLine * getLineByType(enum lineType_e type,
797     struct singleLine * line) {
798        dbgPrintf("getLineByType(%d): ", type);
799        for (; line; line = line->next) {
800     dbgPrintf("%d:%s ", line->type,
801      line->numElements ? line->elements[0].item : "(empty)");
802     if (line->type & type) break;
803        }
804        dbgPrintf(line ? "\n" : " (failed)\n");
805        return line;
806    }
807    
808  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
809      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
810          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
811          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
812              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 818  static int isBracketedTitle(struct singl
818      return 0;      return 0;
819  }  }
820    
821  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
822                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
823      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
824   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;  
825  }  }
826    
827  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
828  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
829      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
830      char * title;      char * title = NULL;
831      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
832      title++;   title = strdup(line->elements[0].item);
833      *(title + strlen(title) - 1) = '\0';   title++;
834     *(title + strlen(title) - 1) = '\0';
835        } else if (line->type == LT_MENUENTRY)
836     title = strdup(line->elements[1].item);
837        else
838     return NULL;
839      return title;      return title;
840  }  }
841    
# Line 389  static void lineInit(struct singleLine * Line 877  static void lineInit(struct singleLine *
877      line->next = NULL;      line->next = NULL;
878  }  }
879    
880  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
881      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
882    
883        newLine->indent = strdup(line->indent);
884        newLine->next = NULL;
885        newLine->type = line->type;
886        newLine->numElements = line->numElements;
887        newLine->elements = malloc(sizeof(*newLine->elements) *
888           newLine->numElements);
889    
890        for (int i = 0; i < newLine->numElements; i++) {
891     newLine->elements[i].indent = strdup(line->elements[i].indent);
892     newLine->elements[i].item = strdup(line->elements[i].item);
893        }
894    
895        return newLine;
896    }
897    
898    static void lineFree(struct singleLine * line) {
899      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
900    
901      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
902   free(line->elements[i].item);   free(line->elements[i].item);
903   free(line->elements[i].indent);   free(line->elements[i].indent);
904      }      }
# Line 405  static void lineFree(struct singleLine * Line 909  static void lineFree(struct singleLine *
909    
910  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
911       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
912      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
913    
914      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
915     /* Need to handle this, because we strip the quotes from
916     * menuentry when read it. */
917     if (line->type == LT_MENUENTRY && i == 1) {
918        if(!isquote(*line->elements[i].item))
919     fprintf(out, "\'%s\'", line->elements[i].item);
920        else
921     fprintf(out, "%s", line->elements[i].item);
922        fprintf(out, "%s", line->elements[i].indent);
923    
924        continue;
925     }
926    
927   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
928      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
929    
930   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
931   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
932        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
933      }      }
934    
935      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 948  static int getNextLine(char ** bufPtr, s
948      char * chptr;      char * chptr;
949      int elementsAlloced = 0;      int elementsAlloced = 0;
950      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
951      int first = 1;      int first = 1;
     int i;  
952    
953      lineFree(line);      lineFree(line);
954    
# Line 489  static int getNextLine(char ** bufPtr, s Line 1002  static int getNextLine(char ** bufPtr, s
1002      if (!line->numElements)      if (!line->numElements)
1003   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
1004      else {      else {
1005   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
1006      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;  
               
1007              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
1008               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
1009              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 1017  static int getNextLine(char ** bufPtr, s
1017      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
1018   char * fullLine;   char * fullLine;
1019   int len;   int len;
  int i;  
1020    
1021   len = strlen(line->indent);   len = strlen(line->indent);
1022   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
1023      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
1024     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1025    
# Line 522  static int getNextLine(char ** bufPtr, s Line 1028  static int getNextLine(char ** bufPtr, s
1028   free(line->indent);   free(line->indent);
1029   line->indent = fullLine;   line->indent = fullLine;
1030    
1031   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1032      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1033      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1034      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 1038  static int getNextLine(char ** bufPtr, s
1038   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
1039   line->numElements = 0;   line->numElements = 0;
1040      }      }
1041     } else {
1042     struct keywordTypes *kw;
1043    
1044     kw = getKeywordByType(line->type, cfi);
1045    
1046     /* space isn't the only separator, we need to split
1047     * elements up more
1048     */
1049     if (!isspace(kw->separatorChar)) {
1050        char indent[2] = "";
1051        indent[0] = kw->separatorChar;
1052        for (int i = 1; i < line->numElements; i++) {
1053     char *p;
1054     int numNewElements;
1055    
1056     numNewElements = 0;
1057     p = line->elements[i].item;
1058     while (*p != '\0') {
1059     if (*p == kw->separatorChar)
1060     numNewElements++;
1061     p++;
1062     }
1063     if (line->numElements + numNewElements >= elementsAlloced) {
1064     elementsAlloced += numNewElements + 5;
1065     line->elements = realloc(line->elements,
1066        sizeof(*line->elements) * elementsAlloced);
1067     }
1068    
1069     for (int j = line->numElements; j > i; j--) {
1070     line->elements[j + numNewElements] = line->elements[j];
1071     }
1072     line->numElements += numNewElements;
1073    
1074     p = line->elements[i].item;
1075     while (*p != '\0') {
1076    
1077     while (*p != kw->separatorChar && *p != '\0') p++;
1078     if (*p == '\0') {
1079     break;
1080     }
1081    
1082     line->elements[i + 1].indent = line->elements[i].indent;
1083     line->elements[i].indent = strdup(indent);
1084     *p++ = '\0';
1085     i++;
1086     line->elements[i].item = strdup(p);
1087     }
1088        }
1089     }
1090   }   }
1091      }      }
1092    
1093      return 0;      return 0;
1094  }  }
1095    
1096    static int isnumber(const char *s)
1097    {
1098        int i;
1099        for (i = 0; s[i] != '\0'; i++)
1100     if (s[i] < '0' || s[i] > '9')
1101        return 0;
1102        return i;
1103    }
1104    
1105  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1106        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1107      int in;      int in;
# Line 549  static struct grubConfig * readConfig(co Line 1113  static struct grubConfig * readConfig(co
1113      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1114      char * end;      char * end;
1115      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1116      int i, len;      int len;
1117      char * buf;      char * buf;
1118    
1119      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1120            printf("Could not find bootloader configuration\n");
1121            exit(1);
1122        } else if (!strcmp(inName, "-")) {
1123   in = 0;   in = 0;
1124      } else {      } else {
1125   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1162  static struct grubConfig * readConfig(co
1162      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1163   }   }
1164    
1165   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1166      sawEntry = 1;      sawEntry = 1;
1167      if (!entry) {      if (!entry) {
1168   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1178  static struct grubConfig * readConfig(co
1178      entry->next = NULL;      entry->next = NULL;
1179   }   }
1180    
1181   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1182        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1183        dbgPrintf("%s", line->indent);
1184        for (int i = 0; i < line->numElements; i++)
1185     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1186        dbgPrintf("\n");
1187        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1188        if (kwType && line->numElements == 3 &&
1189        !strcmp(line->elements[1].item, kwType->key) &&
1190        !is_special_grub2_variable(line->elements[2].item)) {
1191     dbgPrintf("Line sets default config\n");
1192     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1193     defaultLine = line;
1194        }
1195     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1196      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1197      defaultLine = line;      defaultLine = line;
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->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    
1230   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1231      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1232      len = 0;      len = 0;
1233      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1234   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1235   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1236      }      }
1237      buf = malloc(len + 1);      buf = malloc(len + 1);
1238      *buf = '\0';      *buf = '\0';
1239    
1240      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1241   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1242   free(line->elements[i].item);   free(line->elements[i].item);
1243    
# Line 643  static struct grubConfig * readConfig(co Line 1251  static struct grubConfig * readConfig(co
1251      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1252      line->elements[1].item = buf;      line->elements[1].item = buf;
1253      line->numElements = 2;      line->numElements = 2;
1254     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1255        /* let --remove-kernel="TITLE=what" work */
1256        len = 0;
1257        char *extras;
1258        char *title;
1259    
1260        for (int i = 1; i < line->numElements; i++) {
1261     len += strlen(line->elements[i].item);
1262     len += strlen(line->elements[i].indent);
1263        }
1264        buf = malloc(len + 1);
1265        *buf = '\0';
1266    
1267        /* allocate mem for extra flags. */
1268        extras = malloc(len + 1);
1269        *extras = '\0';
1270    
1271        /* get title. */
1272        for (int i = 0; i < line->numElements; i++) {
1273     if (!strcmp(line->elements[i].item, "menuentry"))
1274        continue;
1275     if (isquote(*line->elements[i].item))
1276        title = line->elements[i].item + 1;
1277     else
1278        title = line->elements[i].item;
1279    
1280     len = strlen(title);
1281            if (isquote(title[len-1])) {
1282        strncat(buf, title,len-1);
1283        break;
1284     } else {
1285        strcat(buf, title);
1286        strcat(buf, line->elements[i].indent);
1287     }
1288        }
1289    
1290        /* get extras */
1291        int count = 0;
1292        for (int i = 0; i < line->numElements; i++) {
1293     if (count >= 2) {
1294        strcat(extras, line->elements[i].item);
1295        strcat(extras, line->elements[i].indent);
1296     }
1297    
1298     if (!strcmp(line->elements[i].item, "menuentry"))
1299        continue;
1300    
1301     /* count ' or ", there should be two in menuentry line. */
1302     if (isquote(*line->elements[i].item))
1303        count++;
1304    
1305     len = strlen(line->elements[i].item);
1306    
1307     if (isquote(line->elements[i].item[len -1]))
1308        count++;
1309    
1310     /* ok, we get the final ' or ", others are extras. */
1311                }
1312        line->elements[1].indent =
1313     line->elements[line->numElements - 2].indent;
1314        line->elements[1].item = buf;
1315        line->elements[2].indent =
1316     line->elements[line->numElements - 2].indent;
1317        line->elements[2].item = extras;
1318        line->numElements = 3;
1319   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1320      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1321         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 1324  static struct grubConfig * readConfig(co
1324      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1325   int last, len;   int last, len;
1326    
1327   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1328      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1329     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1330    
1331   last = line->numElements - 1;   last = line->numElements - 1;
1332   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1333   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1334      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1335      }      }
   
1336   }   }
1337    
1338   /* 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 1352  static struct grubConfig * readConfig(co
1352   movedLine = 1;   movedLine = 1;
1353   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1354   }   }
1355    
1356   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1357     which was moved, drop it. */     which was moved, drop it. */
1358   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 1368  static struct grubConfig * readConfig(co
1368   entry->lines = line;   entry->lines = line;
1369      else      else
1370   last->next = line;   last->next = line;
1371        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1372    
1373        /* we could have seen this outside of an entry... if so, we
1374         * ignore it like any other line we don't grok */
1375        if (line->type == LT_ENTRY_END && sawEntry)
1376     sawEntry = 0;
1377   } else {   } else {
1378      if (!cfg->theLines)      if (!cfg->theLines)
1379   cfg->theLines = line;   cfg->theLines = line;
1380      else {      else
1381   last->next = line;   last->next = line;
1382      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1383   }   }
1384    
1385   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1387  static struct grubConfig * readConfig(co
1387    
1388      free(incoming);      free(incoming);
1389    
1390        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1391      if (defaultLine) {      if (defaultLine) {
1392   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1393        cfi->defaultSupportSaved &&
1394        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1395     cfg->cfi->defaultIsSaved = 1;
1396     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1397     if (cfg->cfi->getEnv) {
1398        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1399        if (defTitle) {
1400     int index = 0;
1401     if (isnumber(defTitle)) {
1402        index = atoi(defTitle);
1403        entry = findEntryByIndex(cfg, index);
1404     } else {
1405        entry = findEntryByTitle(cfg, defTitle, &index);
1406     }
1407     if (entry)
1408        cfg->defaultImage = index;
1409        }
1410     }
1411     } else if (cfi->defaultIsVariable) {
1412        char *value = defaultLine->elements[2].item;
1413        while (*value && (*value == '"' || *value == '\'' ||
1414        *value == ' ' || *value == '\t'))
1415     value++;
1416        cfg->defaultImage = strtol(value, &end, 10);
1417        while (*end && (*end == '"' || *end == '\'' ||
1418        *end == ' ' || *end == '\t'))
1419     end++;
1420        if (*end) cfg->defaultImage = -1;
1421     } else if (cfi->defaultSupportSaved &&
1422   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1423      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1424   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1425      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1426      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1427   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1428      i = 0;      int i = 0;
1429      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1430   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1431      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1439  static struct grubConfig * readConfig(co
1439                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1440                  }                  }
1441   i++;   i++;
1442     entry = NULL;
1443      }      }
1444    
1445      if (entry) cfg->defaultImage = i;      if (entry){
1446            cfg->defaultImage = i;
1447        }else{
1448            cfg->defaultImage = -1;
1449        }
1450     }
1451        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1452     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1453     if (defTitle) {
1454        int index = 0;
1455        if (isnumber(defTitle)) {
1456     index = atoi(defTitle);
1457     entry = findEntryByIndex(cfg, index);
1458        } else {
1459     entry = findEntryByTitle(cfg, defTitle, &index);
1460        }
1461        if (entry)
1462     cfg->defaultImage = index;
1463   }   }
1464        } else {
1465            cfg->defaultImage = 0;
1466      }      }
1467    
1468      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1478  static void writeDefault(FILE * out, cha
1478    
1479      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1480   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1481      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1482     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1483     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1484        char *title;
1485        entry = findEntryByIndex(cfg, cfg->defaultImage);
1486        line = getLineByType(LT_MENUENTRY, entry->lines);
1487        if (!line)
1488     line = getLineByType(LT_TITLE, entry->lines);
1489        if (line) {
1490     title = extractTitle(line);
1491     if (title)
1492        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1493        }
1494     }
1495        } else if (cfg->defaultImage > -1) {
1496   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1497      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1498      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1499     cfg->defaultImage);
1500        } else {
1501     fprintf(out, "%sdefault%s%d\n", indent, separator,
1502     cfg->defaultImage);
1503        }
1504   } else {   } else {
1505      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1506    
# Line 769  static void writeDefault(FILE * out, cha Line 1517  static void writeDefault(FILE * out, cha
1517    
1518      if (!entry) return;      if (!entry) return;
1519    
1520      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1521    
1522      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1523   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1551  static int writeConfig(struct grubConfig
1551      int rc;      int rc;
1552    
1553      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1554         directory to / */         directory to the dir of the symlink */
1555      rc = chdir("/");      char *dir = strdupa(outName);
1556        rc = chdir(dirname(dir));
1557      do {      do {
1558   buf = alloca(len + 1);   buf = alloca(len + 1);
1559   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1560   if (rc == len) len += 256;   if (rc == len) len += 256;
1561      } while (rc == len);      } while (rc == len);
1562            
# Line 843  static int writeConfig(struct grubConfig Line 1591  static int writeConfig(struct grubConfig
1591      }      }
1592    
1593      line = cfg->theLines;      line = cfg->theLines;
1594        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1595      while (line) {      while (line) {
1596   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1597     line->numElements == 3 &&
1598     !strcmp(line->elements[1].item, defaultKw->key) &&
1599     !is_special_grub2_variable(line->elements[2].item)) {
1600        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1601        needs &= ~MAIN_DEFAULT;
1602     } else if (line->type == LT_DEFAULT) {
1603      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1604      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1605   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1667  static int numEntries(struct grubConfig
1667      return i;      return i;
1668  }  }
1669    
1670  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1671    int skipRemoved, int flags) {  {
1672      struct singleLine * line;      int fd;
1673      char * fullName;      char buf[65536];
1674      int i;      char *devname;
1675      struct stat sb, sb2;      char *chptr;
1676      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1677    
1678      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1679      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1680                        _PATH_MOUNTED, strerror(errno));
1681      if (!line) return 0;          return NULL;
1682      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1683    
1684      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1685        if (rc <= 0) {
1686            fprintf(stderr, "grubby: failed to read %s: %s\n",
1687                    _PATH_MOUNTED, strerror(errno));
1688            close(fd);
1689            return NULL;
1690        }
1691        close(fd);
1692        buf[rc] = '\0';
1693        chptr = buf;
1694    
1695      fullName = alloca(strlen(bootPrefix) +      char *foundanswer = NULL;
1696        strlen(line->elements[1].item) + 1);  
1697      rootspec = getRootSpecifier(line->elements[1].item);      while (chptr && chptr != buf+rc) {
1698      sprintf(fullName, "%s%s", bootPrefix,          devname = chptr;
1699              line->elements[1].item + ((rootspec != NULL) ?  
1700                                        strlen(rootspec) : 0));          /*
1701      if (access(fullName, R_OK)) return 0;           * The first column of a mtab entry is the device, but if the entry is a
1702             * special device it won't start with /, so move on to the next line.
1703             */
1704            if (*devname != '/') {
1705                chptr = strchr(chptr, '\n');
1706                if (chptr)
1707                    chptr++;
1708                continue;
1709            }
1710    
1711            /* Seek to the next space */
1712            chptr = strchr(chptr, ' ');
1713            if (!chptr) {
1714                fprintf(stderr, "grubby: error parsing %s: %s\n",
1715                        _PATH_MOUNTED, strerror(errno));
1716                return NULL;
1717            }
1718    
1719            /*
1720             * The second column of a mtab entry is the mount point, we are looking
1721             * for '/' obviously.
1722             */
1723            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1724                /* remember the last / entry in mtab */
1725               foundanswer = devname;
1726            }
1727    
1728            /* Next line */
1729            chptr = strchr(chptr, '\n');
1730            if (chptr)
1731                chptr++;
1732        }
1733    
1734        /* Return the last / entry found */
1735        if (foundanswer) {
1736            chptr = strchr(foundanswer, ' ');
1737            *chptr = '\0';
1738            return strdup(foundanswer);
1739        }
1740    
1741        return NULL;
1742    }
1743    
1744    void printEntry(struct singleEntry * entry, FILE *f) {
1745        int i;
1746        struct singleLine * line;
1747    
1748        for (line = entry->lines; line; line = line->next) {
1749     log_message(f, "DBG: %s", line->indent);
1750     for (i = 0; i < line->numElements; i++) {
1751        /* Need to handle this, because we strip the quotes from
1752         * menuentry when read it. */
1753        if (line->type == LT_MENUENTRY && i == 1) {
1754     if(!isquote(*line->elements[i].item))
1755        log_message(f, "\'%s\'", line->elements[i].item);
1756     else
1757        log_message(f, "%s", line->elements[i].item);
1758     log_message(f, "%s", line->elements[i].indent);
1759    
1760     continue;
1761        }
1762        
1763        log_message(f, "%s%s",
1764        line->elements[i].item, line->elements[i].indent);
1765     }
1766     log_message(f, "\n");
1767        }
1768    }
1769    
1770    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1771    {
1772        static int once;
1773        va_list argp, argq;
1774    
1775        va_start(argp, fmt);
1776    
1777        va_copy(argq, argp);
1778        if (!once) {
1779     log_time(NULL);
1780     log_message(NULL, "command line: %s\n", saved_command_line);
1781        }
1782        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1783        log_vmessage(NULL, fmt, argq);
1784    
1785        printEntry(entry, NULL);
1786        va_end(argq);
1787    
1788        if (!debug) {
1789     once = 1;
1790         va_end(argp);
1791     return;
1792        }
1793    
1794        if (okay) {
1795     va_end(argp);
1796     return;
1797        }
1798    
1799        if (!once)
1800     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1801        once = 1;
1802        fprintf(stderr, "DBG: Image entry failed: ");
1803        vfprintf(stderr, fmt, argp);
1804        printEntry(entry, stderr);
1805        va_end(argp);
1806    }
1807    
1808    #define beginswith(s, c) ((s) && (s)[0] == (c))
1809    
1810    static int endswith(const char *s, char c)
1811    {
1812     int slen;
1813    
1814     if (!s || !s[0])
1815     return 0;
1816     slen = strlen(s) - 1;
1817    
1818     return s[slen] == c;
1819    }
1820    
1821    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1822      int skipRemoved, int flags) {
1823        struct singleLine * line;
1824        char * fullName;
1825        int i;
1826        char * dev;
1827        char * rootspec;
1828        char * rootdev;
1829    
1830        if (skipRemoved && entry->skip) {
1831     notSuitablePrintf(entry, 0, "marked to skip\n");
1832     return 0;
1833        }
1834    
1835        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1836        if (!line) {
1837     notSuitablePrintf(entry, 0, "no line found\n");
1838     return 0;
1839        }
1840        if (line->numElements < 2) {
1841     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1842        line->numElements);
1843     return 0;
1844        }
1845    
1846        if (flags & GRUBBY_BADIMAGE_OKAY) {
1847        notSuitablePrintf(entry, 1, "\n");
1848        return 1;
1849        }
1850    
1851        fullName = alloca(strlen(bootPrefix) +
1852          strlen(line->elements[1].item) + 1);
1853        rootspec = getRootSpecifier(line->elements[1].item);
1854        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1855        int hasslash = endswith(bootPrefix, '/') ||
1856         beginswith(line->elements[1].item + rootspec_offset, '/');
1857        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1858                line->elements[1].item + rootspec_offset);
1859        if (access(fullName, R_OK)) {
1860     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1861     return 0;
1862        }
1863      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1864   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1865      if (i < line->numElements) {      if (i < line->numElements) {
1866   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1867      } else {      } else {
1868   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1869   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1870    
1871   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1872      dev = line->elements[1].item;      dev = line->elements[1].item;
1873   } else {   } else {
1874              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1875      /* 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.
1876      line = entry->lines;       */
1877        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1878    
1879              /* failed to find one */              /* failed to find one */
1880              if (!line) return 0;              if (!line) {
1881     notSuitablePrintf(entry, 0, "no line found\n");
1882     return 0;
1883                }
1884    
1885      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1886          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1887      if (i < line->numElements)      if (i < line->numElements)
1888          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1889      else {      else {
1890     notSuitablePrintf(entry, 0, "no root= entry found\n");
1891   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1892          return 0;          return 0;
1893              }              }
1894   }   }
1895      }      }
1896    
1897      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1898   dev += 6;      if (!getpathbyspec(dev)) {
1899            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1900   /* check which device has this label */          return 0;
1901   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1902   if (!dev) return 0;   dev = getpathbyspec(dev);
1903    
1904        rootdev = findDiskForRoot();
1905        if (!rootdev) {
1906            notSuitablePrintf(entry, 0, "can't find root device\n");
1907     return 0;
1908      }      }
1909    
1910      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1911   if (stat(dev, &sb))          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1912      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1913      } else {          free(rootdev);
1914   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1915   if (*end) return 0;      }
1916    
1917        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1918            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1919     getuuidbydev(rootdev), getuuidbydev(dev));
1920     free(rootdev);
1921            return 0;
1922      }      }
     stat("/", &sb2);  
1923    
1924      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1925        notSuitablePrintf(entry, 1, "\n");
1926    
1927      return 1;      return 1;
1928  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1966  struct singleEntry * findEntryByPath(str
1966   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1967   if (!entry) return NULL;   if (!entry) return NULL;
1968    
1969   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;  
   
1970   if (!line) return NULL;   if (!line) return NULL;
1971    
1972   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 2004  struct singleEntry * findEntryByPath(str
2004    
2005   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
2006      prefix = "";      prefix = "";
2007      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
2008      kernel += 6;      kernel += 6;
2009   }   }
2010    
2011   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
2012      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
2013    
2014        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
2015    
2016      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
2017                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
2018          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
2019                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
2020                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2021                      break;   else if (checkType & LT_KERNEL)
2022              }      ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2023                 line = getLineByType(ct, line);
2024              /* have to check multiboot lines too */   if (!line)
2025              if (entry->multiboot) {      break;  /* not found in this entry */
2026                  while (line && line->type != LT_MBMODULE) line = line->next;  
2027                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
2028                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
2029                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
2030                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
2031                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
2032                          break;   kernel + strlen(prefix)))
2033                  }   break;
2034              }   }
2035     if(line->type == LT_MENUENTRY &&
2036     !strcmp(line->elements[1].item, kernel))
2037        break;
2038        }
2039    
2040      i++;      /* make sure this entry has a kernel identifier; this skips
2041         * non-Linux boot entries (could find netbsd etc, though, which is
2042         * unfortunate)
2043         */
2044        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2045     break; /* found 'im! */
2046   }   }
2047    
2048   if (index) *index = i;   if (index) *index = i;
2049      }      }
2050    
2051      if (!entry) return NULL;      return entry;
2052    }
2053    
2054      /* make sure this entry has a kernel identifier; this skips non-Linux  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2055         boot entries (could find netbsd etc, though, which is unfortunate) */        int * index) {
2056      line = entry->lines;      struct singleEntry * entry;
2057      while (line && line->type != LT_KERNEL) line = line->next;      struct singleLine * line;
2058      if (!line) {      int i;
2059   if (!index) index = &i;      char * newtitle;
2060   (*index)++;  
2061   return findEntryByPath(config, kernel, prefix, index);      for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2062     if (index && i < *index)
2063        continue;
2064     line = getLineByType(LT_TITLE, entry->lines);
2065     if (!line)
2066        line = getLineByType(LT_MENUENTRY, entry->lines);
2067     if (!line)
2068        continue;
2069     newtitle = grub2ExtractTitle(line);
2070     if (!newtitle)
2071        continue;
2072     if (!strcmp(title, newtitle))
2073        break;
2074      }      }
2075    
2076        if (!entry)
2077     return NULL;
2078    
2079        if (index)
2080     *index = i;
2081      return entry;      return entry;
2082  }  }
2083    
# Line 1147  struct singleEntry * findTemplate(struct Line 2103  struct singleEntry * findTemplate(struct
2103      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2104      int index;      int index;
2105    
2106      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2107     if (cfg->cfi->getEnv) {
2108        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2109        if (defTitle) {
2110     int index = 0;
2111     if (isnumber(defTitle)) {
2112        index = atoi(defTitle);
2113        entry = findEntryByIndex(cfg, index);
2114     } else {
2115        entry = findEntryByTitle(cfg, defTitle, &index);
2116     }
2117     if (entry)
2118        cfg->defaultImage = index;
2119        }
2120     }
2121        } else if (cfg->defaultImage > -1) {
2122   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2123   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2124      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1200  void markRemovedImage(struct grubConfig Line 2171  void markRemovedImage(struct grubConfig
2171        const char * prefix) {        const char * prefix) {
2172      struct singleEntry * entry;      struct singleEntry * entry;
2173    
2174      if (!image) return;      if (!image)
2175     return;
2176    
2177        /* check and see if we're removing the default image */
2178        if (isdigit(*image)) {
2179     entry = findEntryByPath(cfg, image, prefix, NULL);
2180     if(entry)
2181        entry->skip = 1;
2182     return;
2183        }
2184    
2185      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2186   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 2188  void markRemovedImage(struct grubConfig
2188    
2189  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2190       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2191       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2192      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2193      int i, j;      int i, j;
2194    
2195      if (newIsDefault) {      if (newIsDefault) {
2196   config->defaultImage = 0;   config->defaultImage = 0;
2197   return;   return;
2198        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2199     if (findEntryByIndex(config, index))
2200        config->defaultImage = index;
2201     else
2202        config->defaultImage = -1;
2203     return;
2204      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2205   i = 0;   i = 0;
2206   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 2213  void setDefaultImage(struct grubConfig *
2213    
2214      /* 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
2215         changes */         changes */
2216      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2217     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2218        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2219        return;        return;
2220    
# Line 1286  void displayEntry(struct singleEntry * e Line 2273  void displayEntry(struct singleEntry * e
2273      char * root = NULL;      char * root = NULL;
2274      int i;      int i;
2275    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2276      printf("index=%d\n", index);      printf("index=%d\n", index);
2277    
2278      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2279        if (!line) {
2280            printf("non linux entry\n");
2281            return;
2282        }
2283    
2284        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2285     printf("kernel=%s\n", line->elements[1].item);
2286        else
2287     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2288    
2289      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2290   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2301  void displayEntry(struct singleEntry * e
2301   }   }
2302   printf("\"\n");   printf("\"\n");
2303      } else {      } else {
2304   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2305   if (line) {   if (line) {
2306      char * s;      char * s;
2307    
# Line 1334  void displayEntry(struct singleEntry * e Line 2325  void displayEntry(struct singleEntry * e
2325      }      }
2326    
2327      if (!root) {      if (!root) {
2328   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2329   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2330      root=line->elements[1].item;      root=line->elements[1].item;
2331      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2340  void displayEntry(struct singleEntry * e
2340   printf("root=%s\n", s);   printf("root=%s\n", s);
2341      }      }
2342    
2343      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2344    
2345      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2346   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2347        printf("initrd=");
2348     else
2349        printf("initrd=%s", prefix);
2350    
2351   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2352      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2353   printf("\n");   printf("\n");
2354      }      }
2355    
2356        line = getLineByType(LT_TITLE, entry->lines);
2357        if (line) {
2358     printf("title=%s\n", line->elements[1].item);
2359        } else {
2360     char * title;
2361     line = getLineByType(LT_MENUENTRY, entry->lines);
2362     title = grub2ExtractTitle(line);
2363     if (title)
2364        printf("title=%s\n", title);
2365        }
2366    }
2367    
2368    int isSuseSystem(void) {
2369        const char * path;
2370        const static char default_path[] = "/etc/SuSE-release";
2371    
2372        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2373     path = default_path;
2374    
2375        if (!access(path, R_OK))
2376     return 1;
2377        return 0;
2378    }
2379    
2380    int isSuseGrubConf(const char * path) {
2381        FILE * grubConf;
2382        char * line = NULL;
2383        size_t len = 0, res = 0;
2384    
2385        grubConf = fopen(path, "r");
2386        if (!grubConf) {
2387            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2388     return 0;
2389        }
2390    
2391        while ((res = getline(&line, &len, grubConf)) != -1) {
2392     if (!strncmp(line, "setup", 5)) {
2393        fclose(grubConf);
2394        free(line);
2395        return 1;
2396     }
2397        }
2398    
2399        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2400          path);
2401    
2402        fclose(grubConf);
2403        free(line);
2404        return 0;
2405    }
2406    
2407    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2408        FILE * grubConf;
2409        char * line = NULL;
2410        size_t res = 0, len = 0;
2411    
2412        if (!path) return 1;
2413        if (!lbaPtr) return 1;
2414    
2415        grubConf = fopen(path, "r");
2416        if (!grubConf) return 1;
2417    
2418        while ((res = getline(&line, &len, grubConf)) != -1) {
2419     if (line[res - 1] == '\n')
2420        line[res - 1] = '\0';
2421     else if (len > res)
2422        line[res] = '\0';
2423     else {
2424        line = realloc(line, res + 1);
2425        line[res] = '\0';
2426     }
2427    
2428     if (!strncmp(line, "setup", 5)) {
2429        if (strstr(line, "--force-lba")) {
2430            *lbaPtr = 1;
2431        } else {
2432            *lbaPtr = 0;
2433        }
2434        dbgPrintf("lba: %i\n", *lbaPtr);
2435        break;
2436     }
2437        }
2438    
2439        free(line);
2440        fclose(grubConf);
2441        return 0;
2442    }
2443    
2444    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2445        FILE * grubConf;
2446        char * line = NULL;
2447        size_t res = 0, len = 0;
2448        char * lastParamPtr = NULL;
2449        char * secLastParamPtr = NULL;
2450        char installDeviceNumber = '\0';
2451        char * bounds = NULL;
2452    
2453        if (!path) return 1;
2454        if (!devicePtr) return 1;
2455    
2456        grubConf = fopen(path, "r");
2457        if (!grubConf) return 1;
2458    
2459        while ((res = getline(&line, &len, grubConf)) != -1) {
2460     if (strncmp(line, "setup", 5))
2461        continue;
2462    
2463     if (line[res - 1] == '\n')
2464        line[res - 1] = '\0';
2465     else if (len > res)
2466        line[res] = '\0';
2467     else {
2468        line = realloc(line, res + 1);
2469        line[res] = '\0';
2470     }
2471    
2472     lastParamPtr = bounds = line + res;
2473    
2474     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2475     while (!isspace(*lastParamPtr))
2476        lastParamPtr--;
2477     lastParamPtr++;
2478    
2479     secLastParamPtr = lastParamPtr - 2;
2480     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2481    
2482     if (lastParamPtr + 3 > bounds) {
2483        dbgPrintf("lastParamPtr going over boundary");
2484        fclose(grubConf);
2485        free(line);
2486        return 1;
2487     }
2488     if (!strncmp(lastParamPtr, "(hd", 3))
2489        lastParamPtr += 3;
2490     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2491    
2492     /*
2493     * Second last parameter will decide wether last parameter is
2494     * an IMAGE_DEVICE or INSTALL_DEVICE
2495     */
2496     while (!isspace(*secLastParamPtr))
2497        secLastParamPtr--;
2498     secLastParamPtr++;
2499    
2500     if (secLastParamPtr + 3 > bounds) {
2501        dbgPrintf("secLastParamPtr going over boundary");
2502        fclose(grubConf);
2503        free(line);
2504        return 1;
2505     }
2506     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2507     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2508        secLastParamPtr += 3;
2509        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2510        installDeviceNumber = *secLastParamPtr;
2511     } else {
2512        installDeviceNumber = *lastParamPtr;
2513     }
2514    
2515     *devicePtr = malloc(6);
2516     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2517     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2518     fclose(grubConf);
2519     free(line);
2520     return 0;
2521        }
2522    
2523        free(line);
2524        fclose(grubConf);
2525        return 1;
2526    }
2527    
2528    int grubGetBootFromDeviceMap(const char * device,
2529         char ** bootPtr) {
2530        FILE * deviceMap;
2531        char * line = NULL;
2532        size_t res = 0, len = 0;
2533        char * devicePtr;
2534        char * bounds = NULL;
2535        const char * path;
2536        const static char default_path[] = "/boot/grub/device.map";
2537    
2538        if (!device) return 1;
2539        if (!bootPtr) return 1;
2540    
2541        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2542     path = default_path;
2543    
2544        dbgPrintf("opening grub device.map file from: %s\n", path);
2545        deviceMap = fopen(path, "r");
2546        if (!deviceMap)
2547     return 1;
2548    
2549        while ((res = getline(&line, &len, deviceMap)) != -1) {
2550            if (!strncmp(line, "#", 1))
2551        continue;
2552    
2553     if (line[res - 1] == '\n')
2554        line[res - 1] = '\0';
2555     else if (len > res)
2556        line[res] = '\0';
2557     else {
2558        line = realloc(line, res + 1);
2559        line[res] = '\0';
2560     }
2561    
2562     devicePtr = line;
2563     bounds = line + res;
2564    
2565     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2566        devicePtr++;
2567     dbgPrintf("device: %s\n", devicePtr);
2568    
2569     if (!strncmp(devicePtr, device, strlen(device))) {
2570        devicePtr += strlen(device);
2571        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2572            devicePtr++;
2573    
2574        *bootPtr = strdup(devicePtr);
2575        break;
2576     }
2577        }
2578    
2579        free(line);
2580        fclose(deviceMap);
2581        return 0;
2582    }
2583    
2584    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2585        char * grubDevice;
2586    
2587        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2588     dbgPrintf("error looking for grub installation device\n");
2589        else
2590     dbgPrintf("grubby installation device: %s\n", grubDevice);
2591    
2592        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2593     dbgPrintf("error looking for grub boot device\n");
2594        else
2595     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2596    
2597        free(grubDevice);
2598        return 0;
2599    }
2600    
2601    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2602        /*
2603         * This SuSE grub configuration file at this location is not your average
2604         * grub configuration file, but instead the grub commands used to setup
2605         * grub on that system.
2606         */
2607        const char * path;
2608        const static char default_path[] = "/etc/grub.conf";
2609    
2610        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2611     path = default_path;
2612    
2613        if (!isSuseGrubConf(path)) return 1;
2614    
2615        if (lbaPtr) {
2616            *lbaPtr = 0;
2617            if (suseGrubConfGetLba(path, lbaPtr))
2618                return 1;
2619        }
2620    
2621        if (bootPtr) {
2622            *bootPtr = NULL;
2623            suseGrubConfGetBoot(path, bootPtr);
2624        }
2625    
2626        return 0;
2627  }  }
2628    
2629  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2633  int parseSysconfigGrub(int * lbaPtr, cha
2633      char * start;      char * start;
2634      char * param;      char * param;
2635    
2636      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2637      if (!in) return 1;      if (!in) return 1;
2638    
2639      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2674  int parseSysconfigGrub(int * lbaPtr, cha
2674  }  }
2675    
2676  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2677      char * boot;      char * boot = NULL;
2678      int lba;      int lba;
2679    
2680      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2681   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2682   if (boot) printf("boot=%s\n", boot);      free(boot);
2683        return;
2684     }
2685        } else {
2686            if (parseSysconfigGrub(&lba, &boot)) {
2687        free(boot);
2688        return;
2689     }
2690        }
2691    
2692        if (lba) printf("lba\n");
2693        if (boot) {
2694     printf("boot=%s\n", boot);
2695     free(boot);
2696      }      }
2697  }  }
2698    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2708  int displayInfo(struct grubConfig * conf
2708   return 1;   return 1;
2709      }      }
2710    
2711      /* 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
2712         be a better way */         be a better way */
2713      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2714   dumpSysconfigGrub();   dumpSysconfigGrub();
2715      } else {      } else {
2716   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2717   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2718      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2719   }   }
2720    
2721   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2722   if (line) printf("lba\n");   if (line) printf("lba\n");
2723      }      }
2724    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2733  int displayInfo(struct grubConfig * conf
2733      return 0;      return 0;
2734  }  }
2735    
2736    struct singleLine * addLineTmpl(struct singleEntry * entry,
2737     struct singleLine * tmplLine,
2738     struct singleLine * prevLine,
2739     const char * val,
2740     struct configFileInfo * cfi)
2741    {
2742        struct singleLine * newLine = lineDup(tmplLine);
2743    
2744        if (isEfi && cfi == &grub2ConfigType) {
2745     enum lineType_e old = newLine->type;
2746     newLine->type = preferredLineType(newLine->type, cfi);
2747     if (old != newLine->type)
2748        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2749        }
2750    
2751        if (val) {
2752     /* override the inherited value with our own.
2753     * This is a little weak because it only applies to elements[1]
2754     */
2755     if (newLine->numElements > 1)
2756        removeElement(newLine, 1);
2757     insertElement(newLine, val, 1, cfi);
2758    
2759     /* but try to keep the rootspec from the template... sigh */
2760     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2761        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2762        if (rootspec != NULL) {
2763     free(newLine->elements[1].item);
2764     newLine->elements[1].item =
2765        sdupprintf("%s%s", rootspec, val);
2766        }
2767     }
2768        }
2769    
2770        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2771          newLine->elements[0].item : "");
2772    
2773        if (!entry->lines) {
2774     /* first one on the list */
2775     entry->lines = newLine;
2776        } else if (prevLine) {
2777     /* add after prevLine */
2778     newLine->next = prevLine->next;
2779     prevLine->next = newLine;
2780        }
2781    
2782        return newLine;
2783    }
2784    
2785  /* val may be NULL */  /* val may be NULL */
2786  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2787       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2788       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2789       char * val) {       const char * val) {
2790      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2791      int i;      struct keywordTypes * kw;
2792        struct singleLine tmpl;
2793    
2794      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2795   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2796      if (type != LT_TITLE || !cfi->titleBracketed)       */
2797          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2798     /* we're doing a bracketed title (zipl) */
2799     tmpl.type = type;
2800     tmpl.numElements = 1;
2801     tmpl.elements = alloca(sizeof(*tmpl.elements));
2802     tmpl.elements[0].item = alloca(strlen(val)+3);
2803     sprintf(tmpl.elements[0].item, "[%s]", val);
2804     tmpl.elements[0].indent = "";
2805     val = NULL;
2806        } else if (type == LT_MENUENTRY) {
2807     char *lineend = "--class gnu-linux --class gnu --class os {";
2808     if (!val) {
2809        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2810        abort();
2811     }
2812     kw = getKeywordByType(type, cfi);
2813     if (!kw) {
2814        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2815        abort();
2816     }
2817     tmpl.indent = "";
2818     tmpl.type = type;
2819     tmpl.numElements = 3;
2820     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2821     tmpl.elements[0].item = kw->key;
2822     tmpl.elements[0].indent = alloca(2);
2823     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2824     tmpl.elements[1].item = (char *)val;
2825     tmpl.elements[1].indent = alloca(2);
2826     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2827     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2828     strcpy(tmpl.elements[2].item, lineend);
2829     tmpl.elements[2].indent = "";
2830        } else {
2831     kw = getKeywordByType(type, cfi);
2832     if (!kw) {
2833        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2834        abort();
2835     }
2836     tmpl.type = type;
2837     tmpl.numElements = val ? 2 : 1;
2838     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2839     tmpl.elements[0].item = kw->key;
2840     tmpl.elements[0].indent = alloca(2);
2841     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2842     if (val) {
2843        tmpl.elements[1].item = (char *)val;
2844        tmpl.elements[1].indent = "";
2845     }
2846        }
2847    
2848      /* 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
2849         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2850         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
2851         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2852         differently from the rest) */         differently from the rest) */
2853      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2854   line = entry->lines;   if (line->numElements) prev = line;
2855   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2856   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;  
2857      }      }
2858    
2859      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2860          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2861          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2862          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2863          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2864          line->elements[0].indent = malloc(2);   else
2865          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2866          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2867             if (menuEntry)
2868          if (val) {      tmpl.indent = "\t";
2869              line->elements[1].item = val;   else if (prev == entry->lines)
2870              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2871          }   else
2872      } 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("");  
2873      }      }
2874    
2875      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2876  }  }
2877    
2878  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2897  void removeLine(struct singleEntry * ent
2897      free(line);      free(line);
2898  }  }
2899    
2900    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2901    {
2902        struct singleLine newLine = {
2903     .indent = tmplLine->indent,
2904     .type = tmplLine->type,
2905     .next = tmplLine->next,
2906        };
2907        int firstQuotedItem = -1;
2908        int quoteLen = 0;
2909        int j;
2910        int element = 0;
2911        char *c;
2912    
2913        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2914        strcpy(c, tmplLine->elements[0].item);
2915        insertElement(&newLine, c, element++, cfi);
2916        free(c);
2917        c = NULL;
2918    
2919        for (j = 1; j < tmplLine->numElements; j++) {
2920     if (firstQuotedItem == -1) {
2921        quoteLen += strlen(tmplLine->elements[j].item);
2922        
2923        if (isquote(tmplLine->elements[j].item[0])) {
2924     firstQuotedItem = j;
2925            quoteLen += strlen(tmplLine->elements[j].indent);
2926        } else {
2927     c = malloc(quoteLen + 1);
2928     strcpy(c, tmplLine->elements[j].item);
2929     insertElement(&newLine, c, element++, cfi);
2930     free(c);
2931     quoteLen = 0;
2932        }
2933     } else {
2934        int itemlen = strlen(tmplLine->elements[j].item);
2935        quoteLen += itemlen;
2936        quoteLen += strlen(tmplLine->elements[j].indent);
2937        
2938        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2939     c = malloc(quoteLen + 1);
2940     c[0] = '\0';
2941     for (int i = firstQuotedItem; i < j+1; i++) {
2942        strcat(c, tmplLine->elements[i].item);
2943        strcat(c, tmplLine->elements[i].indent);
2944     }
2945     insertElement(&newLine, c, element++, cfi);
2946     free(c);
2947    
2948     firstQuotedItem = -1;
2949     quoteLen = 0;
2950        }
2951     }
2952        }
2953        while (tmplLine->numElements)
2954     removeElement(tmplLine, 0);
2955        if (tmplLine->elements)
2956     free(tmplLine->elements);
2957    
2958        tmplLine->numElements = newLine.numElements;
2959        tmplLine->elements = newLine.elements;
2960    }
2961    
2962    static void insertElement(struct singleLine * line,
2963      const char * item, int insertHere,
2964      struct configFileInfo * cfi)
2965    {
2966        struct keywordTypes * kw;
2967        char indent[2] = "";
2968    
2969        /* sanity check */
2970        if (insertHere > line->numElements) {
2971     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2972      insertHere, line->numElements);
2973     insertHere = line->numElements;
2974        }
2975    
2976        line->elements = realloc(line->elements, (line->numElements + 1) *
2977         sizeof(*line->elements));
2978        memmove(&line->elements[insertHere+1],
2979        &line->elements[insertHere],
2980        (line->numElements - insertHere) *
2981        sizeof(*line->elements));
2982        line->elements[insertHere].item = strdup(item);
2983    
2984        kw = getKeywordByType(line->type, cfi);
2985    
2986        if (line->numElements == 0) {
2987     indent[0] = '\0';
2988        } else if (insertHere == 0) {
2989     indent[0] = kw->nextChar;
2990        } else if (kw->separatorChar != '\0') {
2991     indent[0] = kw->separatorChar;
2992        } else {
2993     indent[0] = ' ';
2994        }
2995    
2996        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2997     /* move the end-of-line forward */
2998     line->elements[insertHere].indent =
2999        line->elements[insertHere-1].indent;
3000     line->elements[insertHere-1].indent = strdup(indent);
3001        } else {
3002     line->elements[insertHere].indent = strdup(indent);
3003        }
3004    
3005        line->numElements++;
3006    
3007        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
3008          line->elements[0].item,
3009          line->elements[insertHere].item,
3010          line->elements[insertHere].indent,
3011          insertHere);
3012    }
3013    
3014    static void removeElement(struct singleLine * line, int removeHere) {
3015        int i;
3016    
3017        /* sanity check */
3018        if (removeHere >= line->numElements) return;
3019    
3020        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
3021          removeHere, line->elements[removeHere].item);
3022    
3023        free(line->elements[removeHere].item);
3024    
3025        if (removeHere > 1) {
3026     /* previous argument gets this argument's post-indentation */
3027     free(line->elements[removeHere-1].indent);
3028     line->elements[removeHere-1].indent =
3029        line->elements[removeHere].indent;
3030        } else {
3031     free(line->elements[removeHere].indent);
3032        }
3033    
3034        /* now collapse the array, but don't bother to realloc smaller */
3035        for (i = removeHere; i < line->numElements - 1; i++)
3036     line->elements[i] = line->elements[i + 1];
3037    
3038        line->numElements--;
3039    }
3040    
3041  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
3042      char * first, * second;      char * first, * second;
3043      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 3060  int updateActualImage(struct grubConfig
3060      struct singleEntry * entry;      struct singleEntry * entry;
3061      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
3062      int index = 0;      int index = 0;
3063      int i, j, k;      int i, k;
3064      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
3065      const char ** arg;      const char ** arg;
3066      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
3067      int firstElement;      int firstElement;
3068      int *usedElements, *usedArgs;      int *usedElements;
3069        int doreplace;
3070    
3071      if (!image) return 0;      if (!image) return 0;
3072    
# Line 1609  int updateActualImage(struct grubConfig Line 3093  int updateActualImage(struct grubConfig
3093   }   }
3094      }      }
3095    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
3096    
3097      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
3098   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
3099    
3100      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3101   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
3102    
3103      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
3104    
3105      k = 0;   if (multibootArgs && !entry->multiboot)
3106      for (arg = newArgs; *arg; arg++)      continue;
3107          k++;  
3108      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
3109     * LT_KERNELARGS, use that.  Otherwise use
3110     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
3111     */
3112     if (useKernelArgs) {
3113        line = getLineByType(LT_KERNELARGS, entry->lines);
3114        if (!line) {
3115     /* no LT_KERNELARGS, need to add it */
3116     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
3117           cfg->secondaryIndent, NULL);
3118        }
3119        firstElement = 1;
3120    
3121      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
3122   index++;      line = getLineByType(LT_HYPER, entry->lines);
3123        if (!line) {
3124     /* a multiboot entry without LT_HYPER? */
3125     continue;
3126        }
3127        firstElement = 2;
3128    
3129   line = entry->lines;   } else {
3130   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3131   if (!line) continue;      if (!line) {
3132   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3133     continue;
3134          if (entry->multiboot && !multibootArgs) {      }
3135              /* first mb module line is the real kernel */      firstElement = 2;
             while (line && line->type != LT_MBMODULE) line = line->next;  
             firstElement = 2;  
         } else if (useKernelArgs) {  
     while (line && line->type != LT_KERNELARGS) line = line->next;  
     firstElement = 1;  
3136   }   }
3137    
3138   if (!line && useKernelArgs) {   /* handle the elilo case which does:
3139      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
3140      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
3141     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
3142        /* this is a multiboot entry, make sure there's
3143         * -- on the args line
3144         */
3145        for (i = firstElement; i < line->numElements; i++) {
3146     if (!strcmp(line->elements[i].item, "--"))
3147        break;
3148        }
3149        if (i == line->numElements) {
3150     /* assume all existing args are kernel args,
3151     * prepend -- to make it official
3152     */
3153     insertElement(line, "--", firstElement, cfg->cfi);
3154     i = firstElement;
3155        }
3156        if (!multibootArgs) {
3157     /* kernel args start after the -- */
3158     firstElement = i + 1;
3159        }
3160     } else if (cfg->cfi->mbConcatArgs) {
3161        /* this is a non-multiboot entry, remove hyper args */
3162        for (i = firstElement; i < line->numElements; i++) {
3163     if (!strcmp(line->elements[i].item, "--"))
3164        break;
3165        }
3166        if (i < line->numElements) {
3167     /* remove args up to -- */
3168     while (strcmp(line->elements[firstElement].item, "--"))
3169        removeElement(line, firstElement);
3170     /* remove -- */
3171     removeElement(line, firstElement);
3172        }
3173   }   }
3174    
3175          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
3176    
3177          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
3178   for (arg = newArgs; *arg; arg++) {  
3179              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
3180      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
3181     if (multibootArgs && cfg->cfi->mbConcatArgs &&
3182        !strcmp(line->elements[i].item, "--"))
3183     {
3184        /* reached the end of hyper args, insert here */
3185        doreplace = 0;
3186        break;  
3187     }
3188                  if (usedElements[i])                  if (usedElements[i])
3189                      continue;                      continue;
3190   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3191                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3192      break;      break;
3193                  }                  }
3194              }              }
     chptr = strchr(*arg, '=');  
3195    
3196      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
3197   /* replace */   /* direct replacement */
3198   free(line->elements[i].item);   free(line->elements[i].item);
3199   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("");  
  }  
3200    
3201   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
3202   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
3203      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
3204   /* append */   if (rootLine) {
3205   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
3206   (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(" ");  
3207   } else {   } else {
3208      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
3209         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
3210   }   }
3211        }
3212    
3213   line->numElements++;      else {
3214     /* insert/append */
3215     insertElement(line, *arg, i, cfg->cfi);
3216     usedElements = realloc(usedElements, line->numElements *
3217           sizeof(*usedElements));
3218     memmove(&usedElements[i + 1], &usedElements[i],
3219     line->numElements - i - 1);
3220     usedElements[i] = 1;
3221    
3222   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
3223     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
3224     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
3225   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
3226      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
3227      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
3228   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
3229   }   }
3230      }      }
             k++;  
3231   }   }
3232    
3233          free(usedElements);          free(usedElements);
3234    
  /* 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? */  
3235   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
3236      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3237   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3238        !strcmp(line->elements[i].item, "--"))
3239        /* reached the end of hyper args, stop here */
3240        break;
3241     if (!argMatch(line->elements[i].item, *arg)) {
3242        removeElement(line, i);
3243      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;  
3244   }   }
3245        }
3246   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3247        if (useRoot && !strncmp(*arg, "root=", 5)) {
3248   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3249      line->elements[j - 1] = line->elements[j];   if (rootLine)
3250        removeLine(entry, rootLine);
  line->numElements--;  
3251      }      }
3252   }   }
3253    
# Line 1760  int updateActualImage(struct grubConfig Line 3258  int updateActualImage(struct grubConfig
3258   }   }
3259      }      }
3260    
     free(usedArgs);  
3261      free(newArgs);      free(newArgs);
3262      free(oldArgs);      free(oldArgs);
3263    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3283  int updateImage(struct grubConfig * cfg,
3283      return rc;      return rc;
3284  }  }
3285    
3286    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3287     const char * image, const char * prefix, const char * initrd) {
3288        struct singleEntry * entry;
3289        struct singleLine * line, * kernelLine, *endLine = NULL;
3290        int index = 0;
3291    
3292        if (!image) return 0;
3293    
3294        for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) {
3295            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3296            if (!kernelLine) continue;
3297    
3298            if (prefix) {
3299                int prefixLen = strlen(prefix);
3300                if (!strncmp(initrd, prefix, prefixLen))
3301                    initrd += prefixLen;
3302            }
3303     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3304     if (endLine)
3305        removeLine(entry, endLine);
3306            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3307     kernelLine->indent, initrd);
3308            if (!line)
3309        return 1;
3310     if (endLine) {
3311        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3312                if (!line)
3313     return 1;
3314     }
3315    
3316            break;
3317        }
3318    
3319        return 0;
3320    }
3321    
3322    int updateInitrd(struct grubConfig * cfg, const char * image,
3323                     const char * prefix, const char * initrd) {
3324        struct singleEntry * entry;
3325        struct singleLine * line, * kernelLine, *endLine = NULL;
3326        int index = 0;
3327    
3328        if (!image) return 0;
3329    
3330        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3331            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3332            if (!kernelLine) continue;
3333    
3334            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3335            if (line)
3336                removeLine(entry, line);
3337            if (prefix) {
3338                int prefixLen = strlen(prefix);
3339                if (!strncmp(initrd, prefix, prefixLen))
3340                    initrd += prefixLen;
3341            }
3342     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3343     if (endLine)
3344        removeLine(entry, endLine);
3345     enum lineType_e lt;
3346     switch(kernelLine->type) {
3347        case LT_KERNEL:
3348            lt = LT_INITRD;
3349     break;
3350        case LT_KERNEL_EFI:
3351            lt = LT_INITRD_EFI;
3352     break;
3353        case LT_KERNEL_16:
3354            lt = LT_INITRD_16;
3355     break;
3356        default:
3357            lt = preferredLineType(LT_INITRD, cfg->cfi);
3358     }
3359            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3360            if (!line)
3361        return 1;
3362     if (endLine) {
3363        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3364                if (!line)
3365     return 1;
3366     }
3367    
3368            break;
3369        }
3370    
3371        return 0;
3372    }
3373    
3374  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3375      int fd;      int fd;
3376      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3394  int checkDeviceBootloader(const char * d
3394      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3395   return 0;   return 0;
3396    
3397      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3398   offset = boot[2] + 2;   offset = boot[2] + 2;
3399      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3400   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3401      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3402   offset = boot[1] + 2;        offset = boot[1] + 2;
3403            /*
3404     * it looks like grub, when copying stage1 into the mbr, patches stage1
3405     * right after the JMP location, replacing other instructions such as
3406     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3407     * different bytes.
3408     */
3409          if ((bootSect[offset + 1] == NOOP_OPCODE)
3410      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3411     offset = offset + 3;
3412          }
3413      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3414   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3415      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3551  int checkForLilo(struct grubConfig * con
3551      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3552  }  }
3553    
3554    int checkForGrub2(struct grubConfig * config) {
3555        if (!access("/etc/grub.d/", R_OK))
3556     return 2;
3557    
3558        return 1;
3559    }
3560    
3561  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3562      int fd;      int fd;
3563      unsigned char bootSect[512];      unsigned char bootSect[512];
3564      char * boot;      char * boot;
3565        int onSuse = isSuseSystem();
3566    
3567      if (parseSysconfigGrub(NULL, &boot))  
3568   return 0;      if (onSuse) {
3569     if (parseSuseGrubConf(NULL, &boot))
3570        return 0;
3571        } else {
3572     if (parseSysconfigGrub(NULL, &boot))
3573        return 0;
3574        }
3575    
3576      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3577      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3585  int checkForGrub(struct grubConfig * con
3585      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3586   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3587   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3588     close(fd);
3589     return 1;
3590        }
3591        close(fd);
3592    
3593        /* The more elaborate checks do not work on SuSE. The checks done
3594         * seem to be reasonble (at least for now), so just return success
3595         */
3596        if (onSuse)
3597     return 2;
3598    
3599        return checkDeviceBootloader(boot, bootSect);
3600    }
3601    
3602    int checkForExtLinux(struct grubConfig * config) {
3603        int fd;
3604        unsigned char bootSect[512];
3605        char * boot;
3606        char executable[] = "/boot/extlinux/extlinux";
3607    
3608        printf("entered: checkForExtLinux()\n");
3609    
3610        if (parseSysconfigGrub(NULL, &boot))
3611     return 0;
3612    
3613        /* assume grub is not installed -- not an error condition */
3614        if (!boot)
3615     return 0;
3616    
3617        fd = open(executable, O_RDONLY);
3618        if (fd < 0)
3619     /* this doesn't exist if grub hasn't been installed */
3620     return 0;
3621    
3622        if (read(fd, bootSect, 512) != 512) {
3623     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3624     executable, strerror(errno));
3625   return 1;   return 1;
3626      }      }
3627      close(fd);      close(fd);
# Line 1983  int checkForGrub(struct grubConfig * con Line 3629  int checkForGrub(struct grubConfig * con
3629      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3630  }  }
3631    
3632    int checkForYaboot(struct grubConfig * config) {
3633        /*
3634         * This is a simplistic check that we consider good enough for own puporses
3635         *
3636         * If we were to properly check if yaboot is *installed* we'd need to:
3637         * 1) get the system boot device (LT_BOOT)
3638         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3639         *    the content on the boot device
3640         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3641         * 4) check again if binary and boot device contents match
3642         */
3643        if (!access("/etc/yaboot.conf", R_OK))
3644     return 2;
3645    
3646        return 1;
3647    }
3648    
3649    int checkForElilo(struct grubConfig * config) {
3650        if (!access("/etc/elilo.conf", R_OK))
3651     return 2;
3652    
3653        return 1;
3654    }
3655    
3656  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3657      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3658    
# Line 1994  static char * getRootSpecifier(char * st Line 3664  static char * getRootSpecifier(char * st
3664      return rootspec;      return rootspec;
3665  }  }
3666    
3667    static char * getInitrdVal(struct grubConfig * config,
3668       const char * prefix, struct singleLine *tmplLine,
3669       const char * newKernelInitrd,
3670       const char ** extraInitrds, int extraInitrdCount)
3671    {
3672        char *initrdVal, *end;
3673        int i;
3674        size_t totalSize;
3675        size_t prefixLen;
3676        char separatorChar;
3677    
3678        prefixLen = strlen(prefix);
3679        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3680    
3681        for (i = 0; i < extraInitrdCount; i++) {
3682     totalSize += sizeof(separatorChar);
3683     totalSize += strlen(extraInitrds[i]) - prefixLen;
3684        }
3685    
3686        initrdVal = end = malloc(totalSize);
3687    
3688        end = stpcpy (end, newKernelInitrd + prefixLen);
3689    
3690        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3691        for (i = 0; i < extraInitrdCount; i++) {
3692     const char *extraInitrd;
3693     int j;
3694    
3695     extraInitrd = extraInitrds[i] + prefixLen;
3696     /* Don't add entries that are already there */
3697     if (tmplLine != NULL) {
3698        for (j = 2; j < tmplLine->numElements; j++)
3699     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3700        break;
3701    
3702        if (j != tmplLine->numElements)
3703     continue;
3704     }
3705    
3706     *end++ = separatorChar;
3707     end = stpcpy(end, extraInitrd);
3708        }
3709    
3710        return initrdVal;
3711    }
3712    
3713  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3714           const char * prefix,           const char * prefix,
3715   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3716   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3717                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3718                     const char * newMBKernel, const char * newMBKernelArgs,
3719     const char * newDevTreePath) {
3720      struct singleEntry * new;      struct singleEntry * new;
3721      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3722      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3723      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3724    
3725      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3726    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3750  int addNewKernel(struct grubConfig * con
3750      config->entries = new;      config->entries = new;
3751    
3752      /* copy/update from the template */      /* copy/update from the template */
3753      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3754        if (newKernelInitrd)
3755     needs |= NEED_INITRD;
3756      if (newMBKernel) {      if (newMBKernel) {
3757          needs |= KERNEL_MB;          needs |= NEED_MB;
3758          new->multiboot = 1;          new->multiboot = 1;
3759      }      }
3760        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3761     needs |= NEED_DEVTREE;
3762    
3763      if (template) {      if (template) {
3764   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3765      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3766      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3767   indent = tmplLine->indent;   {
3768        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3769    
3770      /* skip comments */      /* skip comments */
3771      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3772      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3773      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3774    
3775      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3776      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3777        /* it's not a multiboot template and this is the kernel
3778              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3779                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3780                  struct singleLine *l;       */
3781                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3782     /* insert the hypervisor first */
3783                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3784                                    config->secondaryIndent,    tmplLine->indent,
3785                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3786                     /* set up for adding the kernel line */
3787                  tmplLine = lastLine;   free(tmplLine->indent);
3788                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3789                      new->lines = l;   needs &= ~NEED_MB;
3790                  } else {      }
3791                      newLine->next = l;      if (needs & NEED_KERNEL) {
3792                      newLine = l;   /* use addLineTmpl to preserve line elements,
3793                  }   * otherwise we could just call addLine.  Unfortunately
3794                  continue;   * this means making some changes to the template
3795              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3796                         template->multiboot && !new->multiboot) {   * change below.
3797                  continue; /* don't need multiboot kernel here */   */
3798              }   struct keywordTypes * mbm_kw =
3799        getKeywordByType(LT_MBMODULE, config->cfi);
3800      if (!new->lines) {   if (mbm_kw) {
3801   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3802   new->lines = newLine;      free(tmplLine->elements[0].item);
3803      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3804   newLine->next = malloc(sizeof(*newLine));   }
3805   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3806      }        newKernelPath + strlen(prefix), config->cfi);
3807     needs &= ~NEED_KERNEL;
3808        }
3809        if (needs & NEED_MB) { /* !mbHyperFirst */
3810     newLine = addLine(new, config->cfi, LT_HYPER,
3811      config->secondaryIndent,
3812      newMBKernel + strlen(prefix));
3813     needs &= ~NEED_MB;
3814        }
3815     } else if (needs & NEED_KERNEL) {
3816        newLine = addLineTmpl(new, tmplLine, newLine,
3817      newKernelPath + strlen(prefix), config->cfi);
3818        needs &= ~NEED_KERNEL;
3819     }
3820    
3821        } else if (tmplLine->type == LT_HYPER &&
3822           tmplLine->numElements >= 2) {
3823     if (needs & NEED_MB) {
3824        newLine = addLineTmpl(new, tmplLine, newLine,
3825      newMBKernel + strlen(prefix), config->cfi);
3826        needs &= ~NEED_MB;
3827     }
3828    
3829      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3830      newLine->next = NULL;         tmplLine->numElements >= 2) {
3831      newLine->type = tmplLine->type;   if (new->multiboot) {
3832      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3833      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3834      newLine->numElements);        newKernelPath +
3835      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3836   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3837   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3838   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3839      }   char *initrdVal;
3840     initrdVal = getInitrdVal(config, prefix, tmplLine,
3841              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3842      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3843                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3844                  if (!template->multiboot) {        initrdVal, config->cfi);
3845                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3846                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3847                  } else {      }
3848                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3849                      repl = newMBKernel;      /* template is multi but new is not,
3850                  }       * insert the kernel in the first module slot
3851                  if (new->multiboot && !template->multiboot) {       */
3852                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3853                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3854                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3855                  }   strdup(getKeywordByType(tmplLine->type,
3856   free(newLine->elements[1].item);   config->cfi)->key);
3857                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3858                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3859                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3860                                                             rootspec,      needs &= ~NEED_KERNEL;
3861                                                             repl +   } else if (needs & NEED_INITRD) {
3862                                                             strlen(prefix));      char *initrdVal;
3863                  } else {      /* template is multi but new is not,
3864                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3865                                                         strlen(prefix));       */
3866                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3867              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3868                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3869                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3870                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3871                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3872                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3873                      newLine->type = LT_KERNEL;      free(initrdVal);
3874                  }      needs &= ~NEED_INITRD;
3875   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;  
3876    
3877   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3878      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3879      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3880        config->cfi->mbInitRdIsModule) {
3881        /* make sure we don't insert the module initrd
3882         * before the module kernel... if we don't do it here,
3883         * it will be inserted following the template.
3884         */
3885        if (!needs & NEED_KERNEL) {
3886     char *initrdVal;
3887    
3888     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3889     newLine = addLine(new, config->cfi, LT_MBMODULE,
3890      config->secondaryIndent,
3891      initrdVal);
3892     free(initrdVal);
3893     needs &= ~NEED_INITRD;
3894        }
3895     } else if (needs & NEED_INITRD) {
3896        char *initrdVal;
3897        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3898        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3899        free(initrdVal);
3900        needs &= ~NEED_INITRD;
3901   }   }
3902    
3903   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3904   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3905   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3906     char *nkt = malloc(strlen(newKernelTitle)+3);
3907     strcpy(nkt, "'");
3908     strcat(nkt, newKernelTitle);
3909     strcat(nkt, "'");
3910     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3911     free(nkt);
3912     needs &= ~NEED_TITLE;
3913      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3914                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3915                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3916                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3917                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3918                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3919                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3920                                             newLine->numElements);     config->cfi->titleBracketed) {
3921        /* addLineTmpl doesn't handle titleBracketed */
3922                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3923                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3924                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3925                  newLine->numElements = 1;   }
3926              }      } else if (tmplLine->type == LT_ECHO) {
3927        requote(tmplLine, config->cfi);
3928        static const char *prefix = "'Loading ";
3929        if (tmplLine->numElements > 1 &&
3930        strstr(tmplLine->elements[1].item, prefix) &&
3931        masterLine->next &&
3932        iskernel(masterLine->next->type)) {
3933     char *newTitle = malloc(strlen(prefix) +
3934     strlen(newKernelTitle) + 2);
3935    
3936     strcpy(newTitle, prefix);
3937     strcat(newTitle, newKernelTitle);
3938     strcat(newTitle, "'");
3939     newLine = addLine(new, config->cfi, LT_ECHO,
3940     tmplLine->indent, newTitle);
3941     free(newTitle);
3942        } else {
3943     /* pass through other lines from the template */
3944     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3945     config->cfi);
3946        }
3947        } else if (tmplLine->type == LT_DEVTREE &&
3948           tmplLine->numElements == 2 && newDevTreePath) {
3949            newLine = addLineTmpl(new, tmplLine, newLine,
3950          newDevTreePath + strlen(prefix),
3951          config->cfi);
3952     needs &= ~NEED_DEVTREE;
3953        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
3954     const char *ndtp = newDevTreePath;
3955     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
3956        ndtp += strlen(prefix);
3957     newLine = addLine(new, config->cfi, LT_DEVTREE,
3958      config->secondaryIndent,
3959      ndtp);
3960     needs &= ~NEED_DEVTREE;
3961     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3962        } else {
3963     /* pass through other lines from the template */
3964     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3965        }
3966   }   }
3967    
3968      } else {      } else {
3969   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3970      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3971     */
3972     switch (config->cfi->entryStart) {
3973        case LT_KERNEL:
3974        case LT_KERNEL_EFI:
3975        case LT_KERNEL_16:
3976     if (new->multiboot && config->cfi->mbHyperFirst) {
3977        /* fall through to LT_HYPER */
3978     } else {
3979        newLine = addLine(new, config->cfi,
3980              preferredLineType(LT_KERNEL, config->cfi),
3981          config->primaryIndent,
3982          newKernelPath + strlen(prefix));
3983        needs &= ~NEED_KERNEL;
3984        break;
3985     }
3986    
3987        case LT_HYPER:
3988     newLine = addLine(new, config->cfi, LT_HYPER,
3989      config->primaryIndent,
3990      newMBKernel + strlen(prefix));
3991     needs &= ~NEED_MB;
3992   break;   break;
         }  
3993    
3994   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3995      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3996       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3997       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3998      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3999       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
4000      default:        config->primaryIndent, nkt);
4001                  /* zipl strikes again */   free(nkt);
4002                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
4003                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
4004                      chptr = newKernelTitle;   break;
4005                      type = LT_TITLE;      }
4006                      break;      case LT_TITLE:
4007                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
4008                      abort();   char * templabel;
4009                  }   int x = 0, y = 0;
4010   }  
4011     templabel = strdup(newKernelTitle);
4012     while( templabel[x]){
4013     if( templabel[x] == ' ' ){
4014     y = x;
4015     while( templabel[y] ){
4016     templabel[y] = templabel[y+1];
4017     y++;
4018     }
4019     }
4020     x++;
4021     }
4022     newLine = addLine(new, config->cfi, LT_TITLE,
4023      config->primaryIndent, templabel);
4024     free(templabel);
4025     }else{
4026     newLine = addLine(new, config->cfi, LT_TITLE,
4027      config->primaryIndent, newKernelTitle);
4028     }
4029     needs &= ~NEED_TITLE;
4030     break;
4031    
4032   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
4033   new->lines = newLine;   abort();
4034     }
4035      }      }
4036    
4037      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
4038          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
4039              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
4040                                config->secondaryIndent,       */
4041                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
4042          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
4043              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
4044                                config->secondaryIndent,    newKernelTitle);
4045                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
4046          /* don't need to check for title as it's guaranteed to have been      }
4047           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
4048           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
4049          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
4050              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
4051                                config->secondaryIndent,   needs &= ~NEED_MB;
4052                                newKernelInitrd + strlen(prefix));      }
4053      } else {      if (needs & NEED_KERNEL) {
4054          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
4055              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4056                                config->secondaryIndent,        config->cfi))
4057                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
4058          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
4059              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
4060                                config->secondaryIndent,    newKernelPath + strlen(prefix));
4061                                newKernelTitle);   needs &= ~NEED_KERNEL;
4062          if (needs & KERNEL_INITRD && newKernelInitrd)      }
4063              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
4064                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
4065                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
4066      newMBKernel + strlen(prefix));
4067     needs &= ~NEED_MB;
4068        }
4069        if (needs & NEED_INITRD) {
4070     char *initrdVal;
4071     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4072     newLine = addLine(new, config->cfi,
4073      (new->multiboot && getKeywordByType(LT_MBMODULE,
4074          config->cfi))
4075       ? LT_MBMODULE
4076       : preferredLineType(LT_INITRD, config->cfi),
4077      config->secondaryIndent,
4078      initrdVal);
4079     free(initrdVal);
4080     needs &= ~NEED_INITRD;
4081        }
4082        if (needs & NEED_DEVTREE) {
4083     newLine = addLine(new, config->cfi, LT_DEVTREE,
4084      config->secondaryIndent,
4085      newDevTreePath);
4086     needs &= ~NEED_DEVTREE;
4087        }
4088    
4089        /* NEEDS_END must be last on bootloaders that need it... */
4090        if (needs & NEED_END) {
4091     newLine = addLine(new, config->cfi, LT_ENTRY_END,
4092     config->secondaryIndent, NULL);
4093     needs &= ~NEED_END;
4094        }
4095        if (needs) {
4096     printf(_("grubby: needs=%d, aborting\n"), needs);
4097     abort();
4098      }      }
4099    
4100      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 4103  int addNewKernel(struct grubConfig * con
4103      return 0;      return 0;
4104  }  }
4105    
4106    static void traceback(int signum)
4107    {
4108        void *array[40];
4109        size_t size;
4110    
4111        signal(SIGSEGV, SIG_DFL);
4112        memset(array, '\0', sizeof (array));
4113        size = backtrace(array, 40);
4114    
4115        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4116                (unsigned long)size);
4117        backtrace_symbols_fd(array, size, STDERR_FILENO);
4118        exit(1);
4119    }
4120    
4121  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4122      poptContext optCon;      poptContext optCon;
4123      char * grubConfig = NULL;      const char * grubConfig = NULL;
4124      char * outputFile = NULL;      char * outputFile = NULL;
4125      int arg = 0;      int arg = 0;
4126      int flags = 0;      int flags = 0;
4127      int badImageOkay = 0;      int badImageOkay = 0;
4128        int configureGrub2 = 0;
4129      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4130      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4131        int configureExtLinux = 0;
4132      int bootloaderProbe = 0;      int bootloaderProbe = 0;
4133        int extraInitrdCount = 0;
4134      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
4135      char * newKernelPath = NULL;      char * newKernelPath = NULL;
4136      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
4137      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4138      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4139      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4140      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4141      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4142      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4143      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 4146  int main(int argc, const char ** argv) {
4146      char * defaultKernel = NULL;      char * defaultKernel = NULL;
4147      char * removeArgs = NULL;      char * removeArgs = NULL;
4148      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4149        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4150        char * envPath = NULL;
4151      const char * chptr = NULL;      const char * chptr = NULL;
4152      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4153      struct grubConfig * config;      struct grubConfig * config;
4154      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4155      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4156      int displayDefault = 0;      int displayDefault = 0;
4157        int displayDefaultIndex = 0;
4158        int displayDefaultTitle = 0;
4159        int defaultIndex = -1;
4160      struct poptOption options[] = {      struct poptOption options[] = {
4161   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4162      _("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 4174  int main(int argc, const char ** argv) {
4174   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4175      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4176      _("bootfs") },      _("bootfs") },
4177  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4178   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4179      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4180  #endif  #endif
4181   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4182      _("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 4187  int main(int argc, const char ** argv) {
4187        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4188        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4189        "template"), NULL },        "template"), NULL },
4190     { "debug", 0, 0, &debug, 0,
4191        _("print debugging information for failures") },
4192   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4193      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4194     { "default-index", 0, 0, &displayDefaultIndex, 0,
4195        _("display the index of the default kernel") },
4196     { "default-title", 0, 0, &displayDefaultTitle, 0,
4197        _("display the title of the default kernel") },
4198     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4199        _("device tree file for new stanza"), _("dtb-path") },
4200   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4201      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4202     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4203        _("force grub2 stanzas to use efi") },
4204     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4205        _("path for environment data"),
4206        _("path") },
4207     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4208        _("configure extlinux bootloader (from syslinux)") },
4209   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4210      _("configure grub bootloader") },      _("configure grub bootloader") },
4211     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4212        _("configure grub2 bootloader") },
4213   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4214      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4215      _("kernel-path") },      _("kernel-path") },
4216   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4217      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4218     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4219        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4220   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4221      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4222   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4236  int main(int argc, const char ** argv) {
4236   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4237      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4238        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4239     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4240        _("make the given entry index the default entry"),
4241        _("entry-index") },
4242   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4243      _("configure silo bootloader") },      _("configure silo bootloader") },
4244   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4256  int main(int argc, const char ** argv) {
4256   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4257      };      };
4258    
4259        useextlinuxmenu=0;
4260    
4261        signal(SIGSEGV, traceback);
4262    
4263        int i = 0;
4264        for (int j = 1; j < argc; j++)
4265     i += strlen(argv[j]) + 1;
4266        saved_command_line = malloc(i);
4267        if (!saved_command_line) {
4268     fprintf(stderr, "grubby: %m\n");
4269     exit(1);
4270        }
4271        saved_command_line[0] = '\0';
4272        for (int j = 1; j < argc; j++) {
4273     strcat(saved_command_line, argv[j]);
4274     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4275        }
4276    
4277      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4278      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4279    
# Line 2391  int main(int argc, const char ** argv) { Line 4283  int main(int argc, const char ** argv) {
4283      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4284      exit(0);      exit(0);
4285      break;      break;
4286      case 'i':
4287        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4288         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4289        } else {
4290     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4291     return 1;
4292        }
4293        break;
4294   }   }
4295      }      }
4296    
# Line 2406  int main(int argc, const char ** argv) { Line 4306  int main(int argc, const char ** argv) {
4306   return 1;   return 1;
4307      }      }
4308    
4309      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4310   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4311     configureExtLinux ) > 1) {
4312   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4313   return 1;   return 1;
4314      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4315   fprintf(stderr,   fprintf(stderr,
4316      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4317   return 1;   return 1;
4318        } else if (configureGrub2) {
4319     cfi = &grub2ConfigType;
4320     if (envPath)
4321        cfi->envFile = envPath;
4322      } else if (configureLilo) {      } else if (configureLilo) {
4323   cfi = &liloConfigType;   cfi = &liloConfigType;
4324      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4331  int main(int argc, const char ** argv) {
4331          cfi = &siloConfigType;          cfi = &siloConfigType;
4332      } else if (configureZipl) {      } else if (configureZipl) {
4333          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4334        } else if (configureExtLinux) {
4335     cfi = &extlinuxConfigType;
4336     useextlinuxmenu=1;
4337      }      }
4338    
4339      if (!cfi) {      if (!cfi) {
4340            if (grub2FindConfig(&grub2ConfigType))
4341        cfi = &grub2ConfigType;
4342     else
4343        #ifdef __ia64__        #ifdef __ia64__
4344   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4345        #elif __powerpc__        #elif __powerpc__
4346   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4347        #elif __sparc__        #elif __sparc__
4348          cfi = &siloConfigType;              cfi = &siloConfigType;
4349        #elif __s390__        #elif __s390__
4350          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4351        #elif __s390x__        #elif __s390x__
4352          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4353        #else        #else
4354   cfi = &grubConfigType;      cfi = &grubConfigType;
4355        #endif        #endif
4356      }      }
4357    
4358      if (!grubConfig)      if (!grubConfig) {
4359   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4360        grubConfig = cfi->findConfig(cfi);
4361     if (!grubConfig)
4362        grubConfig = cfi->defaultConfig;
4363        }
4364    
4365      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4366    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4367    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4368        (defaultIndex >= 0))) {
4369   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4370    "specified option"));    "specified option"));
4371   return 1;   return 1;
4372      }      }
4373    
4374      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4375     removeKernelPath)) {     removeKernelPath)) {
4376   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4377    "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 4381  int main(int argc, const char ** argv) {
4381      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4382   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4383   return 1;   return 1;
4384      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4385    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4386    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4387   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4388   return 1;   return 1;
4389      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4407  int main(int argc, const char ** argv) {
4407   makeDefault = 1;   makeDefault = 1;
4408   defaultKernel = NULL;   defaultKernel = NULL;
4409      }      }
4410        else if (defaultKernel && (defaultIndex >= 0)) {
4411     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4412      "may not be used together\n"));
4413     return 1;
4414        }
4415    
4416      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4417   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4418   "is used\n"));   "is used\n"));
4419   return 1;   return 1;
4420      }      }
4421    
4422      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4423   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4424          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4425     && (defaultIndex == -1)) {
4426   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4427   return 1;   return 1;
4428      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4442  int main(int argc, const char ** argv) {
4442   bootPrefix = "";   bootPrefix = "";
4443      }      }
4444    
4445        if (!cfi->mbAllowExtraInitRds &&
4446     extraInitrdCount > 0) {
4447     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4448     return 1;
4449        }
4450    
4451      if (bootloaderProbe) {      if (bootloaderProbe) {
4452   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4453   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4454    
4455     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4456     if (grub2config) {
4457        gconfig = readConfig(grub2config, &grub2ConfigType);
4458        if (!gconfig)
4459     gr2c = 1;
4460        else
4461     gr2c = checkForGrub2(gconfig);
4462     }
4463    
4464   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4465      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4466        gconfig = readConfig(grubconfig, &grubConfigType);
4467      if (!gconfig)      if (!gconfig)
4468   grc = 1;   grc = 1;
4469      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4478  int main(int argc, const char ** argv) {
4478   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4479   }   }
4480    
4481   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4482        econfig = readConfig(eliloConfigType.defaultConfig,
4483     &eliloConfigType);
4484        if (!econfig)
4485     erc = 1;
4486        else
4487     erc = checkForElilo(econfig);
4488     }
4489    
4490     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4491        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4492        if (!lconfig)
4493     extrc = 1;
4494        else
4495     extrc = checkForExtLinux(lconfig);
4496     }
4497    
4498    
4499     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4500        yconfig = readConfig(yabootConfigType.defaultConfig,
4501     &yabootConfigType);
4502        if (!yconfig)
4503     yrc = 1;
4504        else
4505     yrc = checkForYaboot(yconfig);
4506     }
4507    
4508     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4509     erc == 1)
4510        return 1;
4511    
4512   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4513     if (gr2c == 2) printf("grub2\n");
4514   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4515     if (extrc == 2) printf("extlinux\n");
4516     if (yrc == 2) printf("yaboot\n");
4517     if (erc == 2) printf("elilo\n");
4518    
4519   return 0;   return 0;
4520      }      }
4521    
4522        if (grubConfig == NULL) {
4523     printf("Could not find bootloader configuration file.\n");
4524     exit(1);
4525        }
4526    
4527      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4528      if (!config) return 1;      if (!config) return 1;
4529    
# Line 2557  int main(int argc, const char ** argv) { Line 4533  int main(int argc, const char ** argv) {
4533          char * rootspec;          char * rootspec;
4534    
4535   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4536     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4537     cfi->defaultIsSaved)
4538        config->defaultImage = 0;
4539   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4540   if (!entry) return 0;   if (!entry) return 0;
4541   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4542    
4543   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;  
4544   if (!line) return 0;   if (!line) return 0;
4545    
4546          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4548  int main(int argc, const char ** argv) {
4548                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4549    
4550   return 0;   return 0;
4551    
4552        } else if (displayDefaultTitle) {
4553     struct singleLine * line;
4554     struct singleEntry * entry;
4555    
4556     if (config->defaultImage == -1) return 0;
4557     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4558     cfi->defaultIsSaved)
4559        config->defaultImage = 0;
4560     entry = findEntryByIndex(config, config->defaultImage);
4561     if (!entry) return 0;
4562    
4563     if (!configureGrub2) {
4564      line = getLineByType(LT_TITLE, entry->lines);
4565      if (!line) return 0;
4566      printf("%s\n", line->elements[1].item);
4567    
4568     } else {
4569      char * title;
4570    
4571      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4572      line = getLineByType(LT_MENUENTRY, entry->lines);
4573      if (!line) return 0;
4574      title = grub2ExtractTitle(line);
4575      if (title)
4576        printf("%s\n", title);
4577     }
4578     return 0;
4579    
4580        } else if (displayDefaultIndex) {
4581            if (config->defaultImage == -1) return 0;
4582     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4583     cfi->defaultIsSaved)
4584        config->defaultImage = 0;
4585            printf("%i\n", config->defaultImage);
4586            return 0;
4587    
4588      } else if (kernelInfo)      } else if (kernelInfo)
4589   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4590    
# Line 2581  int main(int argc, const char ** argv) { Line 4596  int main(int argc, const char ** argv) {
4596      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4597      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4598      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4599      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4600      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4601      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4602                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4603        if (updateKernelPath && newKernelInitrd) {
4604        if (newMBKernel) {
4605        if (addMBInitrd(config, newMBKernel, updateKernelPath,
4606     bootPrefix, newKernelInitrd))
4607        return 1;
4608        } else {
4609        if (updateInitrd(config, updateKernelPath, bootPrefix,
4610     newKernelInitrd))
4611     return 1;
4612        }
4613        }
4614      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4615                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4616                       newMBKernel, newMBKernelArgs)) return 1;                       (const char **)extraInitrds, extraInitrdCount,
4617                         newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4618            
4619    
4620      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {
# Line 2597  int main(int argc, const char ** argv) { Line 4624  int main(int argc, const char ** argv) {
4624      }      }
4625    
4626      if (!outputFile)      if (!outputFile)
4627   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4628    
4629      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4630  }  }

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