Magellan Linux

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

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

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

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