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 2263 by niro, Mon Oct 21 14:08:21 2013 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39    #include "log.h"
40    
41    #ifndef DEBUG
42    #define DEBUG 0
43    #endif
44    
45    #if DEBUG
46    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
47    #else
48    #define dbgPrintf(format, args...)
49    #endif
50    
51  #include "mount_by_label.h"  int debug = 0; /* Currently just for template debugging */
52    
53  #define _(A) (A)  #define _(A) (A)
54    
55    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
56  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
57    
58    #define NOOP_OPCODE 0x90
59    #define JMP_SHORT_OPCODE 0xeb
60    
61    int isEfi = 0;
62    
63    char *saved_command_line = NULL;
64    
65  /* comments get lumped in with indention */  /* comments get lumped in with indention */
66  struct lineElement {  struct lineElement {
67      char * item;      char * item;
68      char * indent;      char * indent;
69  };  };
70    
71  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
72         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
73         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
74        LT_KERNEL       = 1 << 2,
75        LT_INITRD       = 1 << 3,
76        LT_HYPER        = 1 << 4,
77        LT_DEFAULT      = 1 << 5,
78        LT_MBMODULE     = 1 << 6,
79        LT_ROOT         = 1 << 7,
80        LT_FALLBACK     = 1 << 8,
81        LT_KERNELARGS   = 1 << 9,
82        LT_BOOT         = 1 << 10,
83        LT_BOOTROOT     = 1 << 11,
84        LT_LBA          = 1 << 12,
85        LT_OTHER        = 1 << 13,
86        LT_GENERIC      = 1 << 14,
87        LT_ECHO    = 1 << 16,
88        LT_MENUENTRY    = 1 << 17,
89        LT_ENTRY_END    = 1 << 18,
90        LT_SET_VARIABLE = 1 << 19,
91        LT_KERNEL_EFI   = 1 << 20,
92        LT_INITRD_EFI   = 1 << 21,
93        LT_UNKNOWN      = 1 << 22,
94    };
95    
96  struct singleLine {  struct singleLine {
97      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 112  struct singleEntry {
112    
113  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */
114    
115  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
116  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
117  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
118  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
119  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
120    #define NEED_MB      (1 << 4)
121    #define NEED_END     (1 << 5)
122    
123  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
124  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
125    #define DEFAULT_SAVED_GRUB2 -3
126    
127  struct keywordTypes {  struct keywordTypes {
128      char * key;      char * key;
129      enum lineType_e type;      enum lineType_e type;
130      char nextChar;      char nextChar;
131  } ;      char separatorChar;
132    };
133    
134    struct configFileInfo;
135    
136    typedef const char *(*findConfigFunc)(struct configFileInfo *);
137    typedef const int (*writeLineFunc)(struct configFileInfo *,
138     struct singleLine *line);
139    typedef char *(*getEnvFunc)(struct configFileInfo *, char *name);
140    typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value);
141    
142  struct configFileInfo {  struct configFileInfo {
143      char * defaultConfig;      char * defaultConfig;
144        findConfigFunc findConfig;
145        writeLineFunc writeLine;
146        getEnvFunc getEnv;
147        setEnvFunc setEnv;
148      struct keywordTypes * keywords;      struct keywordTypes * keywords;
149        int caseInsensitive;
150      int defaultIsIndex;      int defaultIsIndex;
151        int defaultIsVariable;
152      int defaultSupportSaved;      int defaultSupportSaved;
153      enum lineType_e entrySeparator;      int defaultIsSaved;
154        enum lineType_e entryStart;
155        enum lineType_e entryEnd;
156      int needsBootPrefix;      int needsBootPrefix;
157      int argsInQuotes;      int argsInQuotes;
158      int maxTitleLength;      int maxTitleLength;
159      int titleBracketed;      int titleBracketed;
160        int titlePosition;
161        int mbHyperFirst;
162        int mbInitRdIsModule;
163        int mbConcatArgs;
164        int mbAllowExtraInitRds;
165        char *envFile;
166  };  };
167    
168  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 171  struct keywordTypes grubKeywords[] = {
171      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
172      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
173      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
174      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
175      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
176        { "kernel",     LT_HYPER,       ' ' },
177      { NULL,    0, 0 },      { NULL,    0, 0 },
178  };  };
179    
180    const char *grubFindConfig(struct configFileInfo *cfi) {
181        static const char *configFiles[] = {
182     "/boot/grub/grub.conf",
183     "/boot/grub/menu.lst",
184     "/etc/grub.conf",
185     "/boot/grub2/grub.cfg",
186     "/boot/grub2-efi/grub.cfg",
187     NULL
188        };
189        static int i = -1;
190    
191        if (i == -1) {
192     for (i = 0; configFiles[i] != NULL; i++) {
193        dbgPrintf("Checking \"%s\": ", configFiles[i]);
194        if (!access(configFiles[i], R_OK)) {
195     dbgPrintf("found\n");
196     return configFiles[i];
197        }
198        dbgPrintf("not found\n");
199     }
200        }
201        return configFiles[i];
202    }
203    
204  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
205      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
206      grubKeywords,    /* keywords */      .keywords = grubKeywords,
207      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
208      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
209      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
210      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
211      0,    /* argsInQuotes */      .mbHyperFirst = 1,
212      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
213      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
214    };
215    
216    struct keywordTypes grub2Keywords[] = {
217        { "menuentry",  LT_MENUENTRY,   ' ' },
218        { "}",          LT_ENTRY_END,   ' ' },
219        { "echo",       LT_ECHO,        ' ' },
220        { "set",        LT_SET_VARIABLE,' ', '=' },
221        { "root",       LT_BOOTROOT,    ' ' },
222        { "default",    LT_DEFAULT,     ' ' },
223        { "fallback",   LT_FALLBACK,    ' ' },
224        { "linux",      LT_KERNEL,      ' ' },
225        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
226        { "initrd",     LT_INITRD,      ' ', ' ' },
227        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
228        { "module",     LT_MBMODULE,    ' ' },
229        { "kernel",     LT_HYPER,       ' ' },
230        { NULL, 0, 0 },
231    };
232    
233    const char *grub2FindConfig(struct configFileInfo *cfi) {
234        static const char *configFiles[] = {
235     "/boot/grub/grub-efi.cfg",
236     "/boot/grub/grub.cfg",
237     NULL
238        };
239        static int i = -1;
240        static const char *grub_cfg = "/boot/grub/grub.cfg";
241        int rc = -1;
242    
243        if (i == -1) {
244     for (i = 0; configFiles[i] != NULL; i++) {
245        dbgPrintf("Checking \"%s\": ", configFiles[i]);
246        if ((rc = access(configFiles[i], R_OK))) {
247     if (errno == EACCES) {
248        printf("Unable to access bootloader configuration file "
249           "\"%s\": %m\n", configFiles[i]);
250        exit(1);
251     }
252     continue;
253        } else {
254     dbgPrintf("found\n");
255     return configFiles[i];
256        }
257     }
258        }
259    
260        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
261         * that isn't in grub1, and if it exists, return the config file path
262         * that they use. */
263        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
264     dbgPrintf("found\n");
265     return grub_cfg;
266        }
267    
268        dbgPrintf("not found\n");
269        return configFiles[i];
270    }
271    
272    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
273    static char *grub2GetEnv(struct configFileInfo *info, char *name)
274    {
275        static char buf[1025];
276        char *s = NULL;
277        char *ret = NULL;
278        char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
279        int rc = asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name);
280    
281        if (rc < 0)
282     return NULL;
283    
284        FILE *f = popen(s, "r");
285        if (!f)
286     goto out;
287    
288        memset(buf, '\0', sizeof (buf));
289        ret = fgets(buf, 1024, f);
290        pclose(f);
291    
292        if (ret) {
293     ret += strlen(name) + 1;
294     ret[strlen(ret) - 1] = '\0';
295        }
296        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
297    out:
298        free(s);
299        return ret;
300    }
301    
302    static int sPopCount(const char *s, const char *c)
303    {
304        int ret = 0;
305        if (!s)
306     return -1;
307        for (int i = 0; s[i] != '\0'; i++)
308     for (int j = 0; c[j] != '\0'; j++)
309        if (s[i] == c[j])
310     ret++;
311        return ret;
312    }
313    
314    static char *shellEscape(const char *s)
315    {
316        int l = strlen(s) + sPopCount(s, "'") * 2;
317    
318        char *ret = calloc(l+1, sizeof (*ret));
319        if (!ret)
320     return NULL;
321        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
322     if (s[i] == '\'')
323        ret[j++] = '\\';
324     ret[j] = s[i];
325        }
326        return ret;
327    }
328    
329    static void unquote(char *s)
330    {
331        int l = strlen(s);
332    
333        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
334     memmove(s, s+1, l-2);
335     s[l-2] = '\0';
336        }
337    }
338    
339    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
340    {
341        char *s = NULL;
342        int rc = 0;
343        char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
344    
345        unquote(value);
346        value = shellEscape(value);
347        if (!value)
348        return -1;
349    
350        rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value);
351        free(value);
352        if (rc <0)
353     return -1;
354    
355        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
356        rc = system(s);
357        free(s);
358        return rc;
359    }
360    
361    /* this is a gigantic hack to avoid clobbering grub2 variables... */
362    static int is_special_grub2_variable(const char *name)
363    {
364        if (!strcmp(name,"\"${next_entry}\""))
365     return 1;
366        if (!strcmp(name,"\"${prev_saved_entry}\""))
367     return 1;
368        return 0;
369    }
370    
371    int sizeOfSingleLine(struct singleLine * line) {
372      int count = 0;
373    
374      for (int i = 0; i < line->numElements; i++) {
375        int indentSize = 0;
376    
377        count = count + strlen(line->elements[i].item);
378    
379        indentSize = strlen(line->elements[i].indent);
380        if (indentSize > 0)
381          count = count + indentSize;
382        else
383          /* be extra safe and add room for whitespaces */
384          count = count + 1;
385      }
386    
387      /* room for trailing terminator */
388      count = count + 1;
389    
390      return count;
391    }
392    
393    static int isquote(char q)
394    {
395        if (q == '\'' || q == '\"')
396     return 1;
397        return 0;
398    }
399    
400    static int iskernel(enum lineType_e type) {
401        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
402    }
403    
404    static int isinitrd(enum lineType_e type) {
405        return (type == LT_INITRD || type == LT_INITRD_EFI);
406    }
407    
408    char *grub2ExtractTitle(struct singleLine * line) {
409        char * current;
410        char * current_indent;
411        int current_len;
412        int current_indent_len;
413        int i;
414    
415        /* bail out if line does not start with menuentry */
416        if (strcmp(line->elements[0].item, "menuentry"))
417          return NULL;
418    
419        i = 1;
420        current = line->elements[i].item;
421        current_len = strlen(current);
422    
423        /* if second word is quoted, strip the quotes and return single word */
424        if (isquote(*current) && isquote(current[current_len - 1])) {
425     char *tmp;
426    
427     tmp = strdup(current);
428     *(tmp + current_len - 1) = '\0';
429     return ++tmp;
430        }
431    
432        /* if no quotes, return second word verbatim */
433        if (!isquote(*current))
434     return current;
435    
436        /* second element start with a quote, so we have to find the element
437         * whose last character is also quote (assuming it's the closing one) */
438        int resultMaxSize;
439        char * result;
440        
441        resultMaxSize = sizeOfSingleLine(line);
442        result = malloc(resultMaxSize);
443        snprintf(result, resultMaxSize, "%s", ++current);
444        
445        i++;
446        for (; i < line->numElements; ++i) {
447     current = line->elements[i].item;
448     current_len = strlen(current);
449     current_indent = line->elements[i].indent;
450     current_indent_len = strlen(current_indent);
451    
452     strncat(result, current_indent, current_indent_len);
453     if (!isquote(current[current_len-1])) {
454        strncat(result, current, current_len);
455     } else {
456        strncat(result, current, current_len - 1);
457        break;
458     }
459        }
460        return result;
461    }
462    
463    struct configFileInfo grub2ConfigType = {
464        .findConfig = grub2FindConfig,
465        .getEnv = grub2GetEnv,
466        .setEnv = grub2SetEnv,
467        .keywords = grub2Keywords,
468        .defaultIsIndex = 1,
469        .defaultSupportSaved = 1,
470        .defaultIsVariable = 1,
471        .entryStart = LT_MENUENTRY,
472        .entryEnd = LT_ENTRY_END,
473        .titlePosition = 1,
474        .needsBootPrefix = 1,
475        .mbHyperFirst = 1,
476        .mbInitRdIsModule = 1,
477        .mbAllowExtraInitRds = 1,
478  };  };
479    
480  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 508  struct keywordTypes yabootKeywords[] = {
508      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
509      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
510      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
511      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
512      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
513      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
514      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 528  struct keywordTypes liloKeywords[] = {
528      { NULL,    0, 0 },      { NULL,    0, 0 },
529  };  };
530    
531    struct keywordTypes eliloKeywords[] = {
532        { "label",    LT_TITLE,    '=' },
533        { "root",    LT_ROOT,    '=' },
534        { "default",    LT_DEFAULT,    '=' },
535        { "image",    LT_KERNEL,    '=' },
536        { "initrd",    LT_INITRD,    '=' },
537        { "append",    LT_KERNELARGS,  '=' },
538        { "vmm",    LT_HYPER,       '=' },
539        { NULL,    0, 0 },
540    };
541    
542  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
543      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
544      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 560  struct keywordTypes ziplKeywords[] = {
560      { NULL,         0, 0 },      { NULL,         0, 0 },
561  };  };
562    
563    struct keywordTypes extlinuxKeywords[] = {
564        { "label",    LT_TITLE,    ' ' },
565        { "root",    LT_ROOT,    ' ' },
566        { "default",    LT_DEFAULT,    ' ' },
567        { "kernel",    LT_KERNEL,    ' ' },
568        { "initrd",    LT_INITRD,      ' ', ',' },
569        { "append",    LT_KERNELARGS,  ' ' },
570        { "prompt",     LT_UNKNOWN,     ' ' },
571        { NULL,    0, 0 },
572    };
573    int useextlinuxmenu;
574  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
575      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
576      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
577      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
578      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
579      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
580      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
581  };  };
582    
583  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
584      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
585      liloKeywords,    /* keywords */      .keywords = liloKeywords,
586      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
587      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
588      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
589  };  };
590    
591  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
592      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
593      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
594      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
595      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
596      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
597      1,    /* needsBootPrefix */      .maxTitleLength = 15,
598      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
599  };  };
600    
601  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
602      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
603      siloKeywords,    /* keywords */      .keywords = siloKeywords,
604      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
605      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
606      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
607      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
608  };  };
609    
610  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
611      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
612      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
613      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
614      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
615      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
616      0,    /* needsBootPrefix */  };
617      1,    /* argsInQuotes */  
618      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
619      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
620        .keywords = extlinuxKeywords,
621        .caseInsensitive = 1,
622        .entryStart = LT_TITLE,
623        .needsBootPrefix = 1,
624        .maxTitleLength = 255,
625        .mbAllowExtraInitRds = 1,
626  };  };
627    
628  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 637  struct grubConfig {
637      struct configFileInfo * cfi;      struct configFileInfo * cfi;
638  };  };
639    
640    blkid_cache blkid;
641    
642  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
643  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
644       const char * path, const char * prefix,       const char * path, const char * prefix,
645       int * index);       int * index);
646  static char * strndup(char * from, int len);  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
647          int * index);
648  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
649  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
650    struct singleLine * lineDup(struct singleLine * line);
651  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
652  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
653       struct configFileInfo * cfi);       struct configFileInfo * cfi);
654  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
655         struct configFileInfo * cfi);         struct configFileInfo * cfi);
656  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
657    static void requote(struct singleLine *line, struct configFileInfo * cfi);
658  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
659      char * to;    const char * item, int insertHere,
660      struct configFileInfo * cfi);
661      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
662      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
663      to[len] = '\0';        struct configFileInfo * cfi);
664    static enum lineType_e getTypeByKeyword(char * keyword,
665      return to;   struct configFileInfo * cfi);
666  }  static struct singleLine * getLineByType(enum lineType_e type,
667     struct singleLine * line);
668    static int checkForExtLinux(struct grubConfig * config);
669    struct singleLine * addLineTmpl(struct singleEntry * entry,
670                                    struct singleLine * tmplLine,
671                                    struct singleLine * prevLine,
672                                    const char * val,
673     struct configFileInfo * cfi);
674    struct singleLine *  addLine(struct singleEntry * entry,
675                                 struct configFileInfo * cfi,
676                                 enum lineType_e type, char * defaultIndent,
677                                 const char * val);
678    
679  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
680  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 709  static char * sdupprintf(const char *for
709      return buf;      return buf;
710  }  }
711    
712    static enum lineType_e preferredLineType(enum lineType_e type,
713     struct configFileInfo *cfi) {
714        if (isEfi && cfi == &grub2ConfigType) {
715     switch (type) {
716     case LT_KERNEL:
717        return LT_KERNEL_EFI;
718     case LT_INITRD:
719        return LT_INITRD_EFI;
720     default:
721        return type;
722     }
723        }
724        return type;
725    }
726    
727    static struct keywordTypes * getKeywordByType(enum lineType_e type,
728          struct configFileInfo * cfi) {
729        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
730     if (kw->type == type)
731        return kw;
732        }
733        return NULL;
734    }
735    
736    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
737        struct keywordTypes *kt = getKeywordByType(type, cfi);
738        if (kt)
739     return kt->key;
740        return "unknown";
741    }
742    
743    static char * getpathbyspec(char *device) {
744        if (!blkid)
745            blkid_get_cache(&blkid, NULL);
746    
747        return blkid_get_devname(blkid, device, NULL);
748    }
749    
750    static char * getuuidbydev(char *device) {
751        if (!blkid)
752     blkid_get_cache(&blkid, NULL);
753    
754        return blkid_get_tag_value(blkid, "UUID", device);
755    }
756    
757    static enum lineType_e getTypeByKeyword(char * keyword,
758     struct configFileInfo * cfi) {
759        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
760     if (cfi->caseInsensitive) {
761        if (!strcasecmp(keyword, kw->key))
762                    return kw->type;
763     } else {
764        if (!strcmp(keyword, kw->key))
765            return kw->type;
766     }
767        }
768        return LT_UNKNOWN;
769    }
770    
771    static struct singleLine * getLineByType(enum lineType_e type,
772     struct singleLine * line) {
773        dbgPrintf("getLineByType(%d): ", type);
774        for (; line; line = line->next) {
775     dbgPrintf("%d:%s ", line->type,
776      line->numElements ? line->elements[0].item : "(empty)");
777     if (line->type & type) break;
778        }
779        dbgPrintf(line ? "\n" : " (failed)\n");
780        return line;
781    }
782    
783  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
784      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
785          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
786          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
787              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 793  static int isBracketedTitle(struct singl
793      return 0;      return 0;
794  }  }
795    
796  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
797                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
798      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
799   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;  
800  }  }
801    
802  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
803  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
804      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
805      char * title;      char * title = NULL;
806      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
807      title++;   title = strdup(line->elements[0].item);
808      *(title + strlen(title) - 1) = '\0';   title++;
809     *(title + strlen(title) - 1) = '\0';
810        } else if (line->type == LT_MENUENTRY)
811     title = strdup(line->elements[1].item);
812        else
813     return NULL;
814      return title;      return title;
815  }  }
816    
# Line 389  static void lineInit(struct singleLine * Line 852  static void lineInit(struct singleLine *
852      line->next = NULL;      line->next = NULL;
853  }  }
854    
855  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
856      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
857    
858        newLine->indent = strdup(line->indent);
859        newLine->next = NULL;
860        newLine->type = line->type;
861        newLine->numElements = line->numElements;
862        newLine->elements = malloc(sizeof(*newLine->elements) *
863           newLine->numElements);
864    
865        for (int i = 0; i < newLine->numElements; i++) {
866     newLine->elements[i].indent = strdup(line->elements[i].indent);
867     newLine->elements[i].item = strdup(line->elements[i].item);
868        }
869    
870        return newLine;
871    }
872    
873    static void lineFree(struct singleLine * line) {
874      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
875    
876      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
877   free(line->elements[i].item);   free(line->elements[i].item);
878   free(line->elements[i].indent);   free(line->elements[i].indent);
879      }      }
# Line 405  static void lineFree(struct singleLine * Line 884  static void lineFree(struct singleLine *
884    
885  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
886       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
887      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
888    
889      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
890     /* Need to handle this, because we strip the quotes from
891     * menuentry when read it. */
892     if (line->type == LT_MENUENTRY && i == 1) {
893        if(!isquote(*line->elements[i].item))
894     fprintf(out, "\'%s\'", line->elements[i].item);
895        else
896     fprintf(out, "%s", line->elements[i].item);
897        fprintf(out, "%s", line->elements[i].indent);
898    
899        continue;
900     }
901    
902   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
903      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
904    
905   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
906   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
907        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
908      }      }
909    
910      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 923  static int getNextLine(char ** bufPtr, s
923      char * chptr;      char * chptr;
924      int elementsAlloced = 0;      int elementsAlloced = 0;
925      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
926      int first = 1;      int first = 1;
     int i;  
927    
928      lineFree(line);      lineFree(line);
929    
# Line 489  static int getNextLine(char ** bufPtr, s Line 977  static int getNextLine(char ** bufPtr, s
977      if (!line->numElements)      if (!line->numElements)
978   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
979      else {      else {
980   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
981      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;  
               
982              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
983               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
984              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 992  static int getNextLine(char ** bufPtr, s
992      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
993   char * fullLine;   char * fullLine;
994   int len;   int len;
  int i;  
995    
996   len = strlen(line->indent);   len = strlen(line->indent);
997   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
998      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
999     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1000    
# Line 522  static int getNextLine(char ** bufPtr, s Line 1003  static int getNextLine(char ** bufPtr, s
1003   free(line->indent);   free(line->indent);
1004   line->indent = fullLine;   line->indent = fullLine;
1005    
1006   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1007      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1008      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1009      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 1013  static int getNextLine(char ** bufPtr, s
1013   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
1014   line->numElements = 0;   line->numElements = 0;
1015      }      }
1016     } else {
1017     struct keywordTypes *kw;
1018    
1019     kw = getKeywordByType(line->type, cfi);
1020    
1021     /* space isn't the only separator, we need to split
1022     * elements up more
1023     */
1024     if (!isspace(kw->separatorChar)) {
1025        char indent[2] = "";
1026        indent[0] = kw->separatorChar;
1027        for (int i = 1; i < line->numElements; i++) {
1028     char *p;
1029     int numNewElements;
1030    
1031     numNewElements = 0;
1032     p = line->elements[i].item;
1033     while (*p != '\0') {
1034     if (*p == kw->separatorChar)
1035     numNewElements++;
1036     p++;
1037     }
1038     if (line->numElements + numNewElements >= elementsAlloced) {
1039     elementsAlloced += numNewElements + 5;
1040     line->elements = realloc(line->elements,
1041        sizeof(*line->elements) * elementsAlloced);
1042     }
1043    
1044     for (int j = line->numElements; j > i; j--) {
1045     line->elements[j + numNewElements] = line->elements[j];
1046     }
1047     line->numElements += numNewElements;
1048    
1049     p = line->elements[i].item;
1050     while (*p != '\0') {
1051    
1052     while (*p != kw->separatorChar && *p != '\0') p++;
1053     if (*p == '\0') {
1054     break;
1055     }
1056    
1057     line->elements[i + 1].indent = line->elements[i].indent;
1058     line->elements[i].indent = strdup(indent);
1059     *p++ = '\0';
1060     i++;
1061     line->elements[i].item = strdup(p);
1062     }
1063        }
1064     }
1065   }   }
1066      }      }
1067    
1068      return 0;      return 0;
1069  }  }
1070    
1071    static int isnumber(const char *s)
1072    {
1073        int i;
1074        for (i = 0; s[i] != '\0'; i++)
1075     if (s[i] < '0' || s[i] > '9')
1076        return 0;
1077        return i;
1078    }
1079    
1080  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1081        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1082      int in;      int in;
# Line 549  static struct grubConfig * readConfig(co Line 1088  static struct grubConfig * readConfig(co
1088      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1089      char * end;      char * end;
1090      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1091      int i, len;      int len;
1092      char * buf;      char * buf;
1093    
1094      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1095            printf("Could not find bootloader configuration\n");
1096            exit(1);
1097        } else if (!strcmp(inName, "-")) {
1098   in = 0;   in = 0;
1099      } else {      } else {
1100   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 595  static struct grubConfig * readConfig(co Line 1137  static struct grubConfig * readConfig(co
1137      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1138   }   }
1139    
1140   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1141      sawEntry = 1;      sawEntry = 1;
1142      if (!entry) {      if (!entry) {
1143   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1153  static struct grubConfig * readConfig(co
1153      entry->next = NULL;      entry->next = NULL;
1154   }   }
1155    
1156   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1157        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1158        dbgPrintf("%s", line->indent);
1159        for (int i = 0; i < line->numElements; i++)
1160     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1161        dbgPrintf("\n");
1162        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1163        if (kwType && line->numElements == 3 &&
1164        !strcmp(line->elements[1].item, kwType->key) &&
1165        !is_special_grub2_variable(line->elements[2].item)) {
1166     dbgPrintf("Line sets default config\n");
1167     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1168     defaultLine = line;
1169        }
1170     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1171      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1172      defaultLine = line;      defaultLine = line;
1173    
1174            } else if (iskernel(line->type)) {
1175        /* if by some freak chance this is multiboot and the "module"
1176         * lines came earlier in the template, make sure to use LT_HYPER
1177         * instead of LT_KERNEL now
1178         */
1179        if (entry->multiboot)
1180     line->type = LT_HYPER;
1181    
1182          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1183        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1184         * instead, now that we know this is a multiboot entry.
1185         * This only applies to grub, but that's the only place we
1186         * should find LT_MBMODULE lines anyway.
1187         */
1188        for (struct singleLine *l = entry->lines; l; l = l->next) {
1189     if (l->type == LT_HYPER)
1190        break;
1191     else if (iskernel(l->type)) {
1192        l->type = LT_HYPER;
1193        break;
1194     }
1195        }
1196              entry->multiboot = 1;              entry->multiboot = 1;
1197    
1198     } else if (line->type == LT_HYPER) {
1199        entry->multiboot = 1;
1200    
1201   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1202      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1203      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1204    
1205   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1206      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1207      len = 0;      len = 0;
1208      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1209   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1210   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1211      }      }
1212      buf = malloc(len + 1);      buf = malloc(len + 1);
1213      *buf = '\0';      *buf = '\0';
1214    
1215      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1216   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1217   free(line->elements[i].item);   free(line->elements[i].item);
1218    
# Line 643  static struct grubConfig * readConfig(co Line 1226  static struct grubConfig * readConfig(co
1226      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1227      line->elements[1].item = buf;      line->elements[1].item = buf;
1228      line->numElements = 2;      line->numElements = 2;
1229     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1230        /* let --remove-kernel="TITLE=what" work */
1231        len = 0;
1232        char *extras;
1233        char *title;
1234    
1235        for (int i = 1; i < line->numElements; i++) {
1236     len += strlen(line->elements[i].item);
1237     len += strlen(line->elements[i].indent);
1238        }
1239        buf = malloc(len + 1);
1240        *buf = '\0';
1241    
1242        /* allocate mem for extra flags. */
1243        extras = malloc(len + 1);
1244        *extras = '\0';
1245    
1246        /* get title. */
1247        for (int i = 0; i < line->numElements; i++) {
1248     if (!strcmp(line->elements[i].item, "menuentry"))
1249        continue;
1250     if (isquote(*line->elements[i].item))
1251        title = line->elements[i].item + 1;
1252     else
1253        title = line->elements[i].item;
1254    
1255     len = strlen(title);
1256            if (isquote(title[len-1])) {
1257        strncat(buf, title,len-1);
1258        break;
1259     } else {
1260        strcat(buf, title);
1261        strcat(buf, line->elements[i].indent);
1262     }
1263        }
1264    
1265        /* get extras */
1266        int count = 0;
1267        for (int i = 0; i < line->numElements; i++) {
1268     if (count >= 2) {
1269        strcat(extras, line->elements[i].item);
1270        strcat(extras, line->elements[i].indent);
1271     }
1272    
1273     if (!strcmp(line->elements[i].item, "menuentry"))
1274        continue;
1275    
1276     /* count ' or ", there should be two in menuentry line. */
1277     if (isquote(*line->elements[i].item))
1278        count++;
1279    
1280     len = strlen(line->elements[i].item);
1281    
1282     if (isquote(line->elements[i].item[len -1]))
1283        count++;
1284    
1285     /* ok, we get the final ' or ", others are extras. */
1286                }
1287        line->elements[1].indent =
1288     line->elements[line->numElements - 2].indent;
1289        line->elements[1].item = buf;
1290        line->elements[2].indent =
1291     line->elements[line->numElements - 2].indent;
1292        line->elements[2].item = extras;
1293        line->numElements = 3;
1294   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1295      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1296         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 1299  static struct grubConfig * readConfig(co
1299      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1300   int last, len;   int last, len;
1301    
1302   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1303      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1304     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1305    
1306   last = line->numElements - 1;   last = line->numElements - 1;
1307   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1308   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1309      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1310      }      }
   
1311   }   }
1312    
1313   /* 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 1327  static struct grubConfig * readConfig(co
1327   movedLine = 1;   movedLine = 1;
1328   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1329   }   }
1330    
1331   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1332     which was moved, drop it. */     which was moved, drop it. */
1333   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 1343  static struct grubConfig * readConfig(co
1343   entry->lines = line;   entry->lines = line;
1344      else      else
1345   last->next = line;   last->next = line;
1346        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1347    
1348        /* we could have seen this outside of an entry... if so, we
1349         * ignore it like any other line we don't grok */
1350        if (line->type == LT_ENTRY_END && sawEntry)
1351     sawEntry = 0;
1352   } else {   } else {
1353      if (!cfg->theLines)      if (!cfg->theLines)
1354   cfg->theLines = line;   cfg->theLines = line;
1355      else {      else
1356   last->next = line;   last->next = line;
1357      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1358   }   }
1359    
1360   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1362  static struct grubConfig * readConfig(co
1362    
1363      free(incoming);      free(incoming);
1364    
1365        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1366      if (defaultLine) {      if (defaultLine) {
1367   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1368        cfi->defaultSupportSaved &&
1369        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1370     cfg->cfi->defaultIsSaved = 1;
1371     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1372     if (cfg->cfi->getEnv) {
1373        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1374        if (defTitle) {
1375     int index = 0;
1376     if (isnumber(defTitle)) {
1377        index = atoi(defTitle);
1378        entry = findEntryByIndex(cfg, index);
1379     } else {
1380        entry = findEntryByTitle(cfg, defTitle, &index);
1381     }
1382     if (entry)
1383        cfg->defaultImage = index;
1384        }
1385     }
1386     } else if (cfi->defaultIsVariable) {
1387        char *value = defaultLine->elements[2].item;
1388        while (*value && (*value == '"' || *value == '\'' ||
1389        *value == ' ' || *value == '\t'))
1390     value++;
1391        cfg->defaultImage = strtol(value, &end, 10);
1392        while (*end && (*end == '"' || *end == '\'' ||
1393        *end == ' ' || *end == '\t'))
1394     end++;
1395        if (*end) cfg->defaultImage = -1;
1396     } else if (cfi->defaultSupportSaved &&
1397   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1398      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1399   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1400      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1401      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1402   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1403      i = 0;      int i = 0;
1404      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1405   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1406      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1414  static struct grubConfig * readConfig(co
1414                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1415                  }                  }
1416   i++;   i++;
1417     entry = NULL;
1418      }      }
1419    
1420      if (entry) cfg->defaultImage = i;      if (entry){
1421            cfg->defaultImage = i;
1422        }else{
1423            cfg->defaultImage = -1;
1424        }
1425   }   }
1426        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1427     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1428     if (defTitle) {
1429        int index = 0;
1430        if (isnumber(defTitle)) {
1431     index = atoi(defTitle);
1432     entry = findEntryByIndex(cfg, index);
1433        } else {
1434     entry = findEntryByTitle(cfg, defTitle, &index);
1435        }
1436        if (entry)
1437     cfg->defaultImage = index;
1438     }
1439        } else {
1440            cfg->defaultImage = 0;
1441      }      }
1442    
1443      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1453  static void writeDefault(FILE * out, cha
1453    
1454      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1455   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1456      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1457     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1458     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1459        char *title;
1460        entry = findEntryByIndex(cfg, cfg->defaultImage);
1461        line = getLineByType(LT_MENUENTRY, entry->lines);
1462        if (!line)
1463     line = getLineByType(LT_TITLE, entry->lines);
1464        if (line) {
1465     title = extractTitle(line);
1466     if (title)
1467        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1468        }
1469     }
1470        } else if (cfg->defaultImage > -1) {
1471   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1472      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1473      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1474     cfg->defaultImage);
1475        } else {
1476     fprintf(out, "%sdefault%s%d\n", indent, separator,
1477     cfg->defaultImage);
1478        }
1479   } else {   } else {
1480      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1481    
# Line 769  static void writeDefault(FILE * out, cha Line 1492  static void writeDefault(FILE * out, cha
1492    
1493      if (!entry) return;      if (!entry) return;
1494    
1495      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1496    
1497      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1498   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1526  static int writeConfig(struct grubConfig
1526      int rc;      int rc;
1527    
1528      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1529         directory to / */         directory to the dir of the symlink */
1530      rc = chdir("/");      char *dir = strdupa(outName);
1531        rc = chdir(dirname(dir));
1532      do {      do {
1533   buf = alloca(len + 1);   buf = alloca(len + 1);
1534   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1535   if (rc == len) len += 256;   if (rc == len) len += 256;
1536      } while (rc == len);      } while (rc == len);
1537            
# Line 843  static int writeConfig(struct grubConfig Line 1566  static int writeConfig(struct grubConfig
1566      }      }
1567    
1568      line = cfg->theLines;      line = cfg->theLines;
1569        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1570      while (line) {      while (line) {
1571   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1572     line->numElements == 3 &&
1573     !strcmp(line->elements[1].item, defaultKw->key) &&
1574     !is_special_grub2_variable(line->elements[2].item)) {
1575        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1576        needs &= ~MAIN_DEFAULT;
1577     } else if (line->type == LT_DEFAULT) {
1578      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1579      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1580   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1642  static int numEntries(struct grubConfig
1642      return i;      return i;
1643  }  }
1644    
1645  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1646    int skipRemoved, int flags) {  {
1647      struct singleLine * line;      int fd;
1648      char * fullName;      char buf[65536];
1649      int i;      char *devname;
1650      struct stat sb, sb2;      char *chptr;
1651      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1652    
1653      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1654      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1655                        _PATH_MOUNTED, strerror(errno));
1656      if (!line) return 0;          return NULL;
1657      if (skipRemoved && entry->skip) return 0;      }
     if (line->numElements < 2) return 0;  
1658    
1659      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      rc = read(fd, buf, sizeof(buf) - 1);
1660        if (rc <= 0) {
1661            fprintf(stderr, "grubby: failed to read %s: %s\n",
1662                    _PATH_MOUNTED, strerror(errno));
1663            close(fd);
1664            return NULL;
1665        }
1666        close(fd);
1667        buf[rc] = '\0';
1668        chptr = buf;
1669    
1670      fullName = alloca(strlen(bootPrefix) +      char *foundanswer = NULL;
       strlen(line->elements[1].item) + 1);  
     rootspec = getRootSpecifier(line->elements[1].item);  
     sprintf(fullName, "%s%s", bootPrefix,  
             line->elements[1].item + ((rootspec != NULL) ?  
                                       strlen(rootspec) : 0));  
     if (access(fullName, R_OK)) return 0;  
1671    
1672      for (i = 2; i < line->numElements; i++)      while (chptr && chptr != buf+rc) {
1673   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          devname = chptr;
1674      if (i < line->numElements) {  
1675   dev = line->elements[i].item + 5;          /*
1676             * The first column of a mtab entry is the device, but if the entry is a
1677             * special device it won't start with /, so move on to the next line.
1678             */
1679            if (*devname != '/') {
1680                chptr = strchr(chptr, '\n');
1681                if (chptr)
1682                    chptr++;
1683                continue;
1684            }
1685    
1686            /* Seek to the next space */
1687            chptr = strchr(chptr, ' ');
1688            if (!chptr) {
1689                fprintf(stderr, "grubby: error parsing %s: %s\n",
1690                        _PATH_MOUNTED, strerror(errno));
1691                return NULL;
1692            }
1693    
1694            /*
1695             * The second column of a mtab entry is the mount point, we are looking
1696             * for '/' obviously.
1697             */
1698            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1699                /* remember the last / entry in mtab */
1700               foundanswer = devname;
1701            }
1702    
1703            /* Next line */
1704            chptr = strchr(chptr, '\n');
1705            if (chptr)
1706                chptr++;
1707        }
1708    
1709        /* Return the last / entry found */
1710        if (foundanswer) {
1711            chptr = strchr(foundanswer, ' ');
1712            *chptr = '\0';
1713            return strdup(foundanswer);
1714        }
1715    
1716        return NULL;
1717    }
1718    
1719    void printEntry(struct singleEntry * entry, FILE *f) {
1720        int i;
1721        struct singleLine * line;
1722    
1723        for (line = entry->lines; line; line = line->next) {
1724     log_message(f, "DBG: %s", line->indent);
1725     for (i = 0; i < line->numElements; i++) {
1726        /* Need to handle this, because we strip the quotes from
1727         * menuentry when read it. */
1728        if (line->type == LT_MENUENTRY && i == 1) {
1729     if(!isquote(*line->elements[i].item))
1730        log_message(f, "\'%s\'", line->elements[i].item);
1731     else
1732        log_message(f, "%s", line->elements[i].item);
1733     log_message(f, "%s", line->elements[i].indent);
1734    
1735     continue;
1736        }
1737        
1738        log_message(f, "%s%s",
1739        line->elements[i].item, line->elements[i].indent);
1740     }
1741     log_message(f, "\n");
1742        }
1743    }
1744    
1745    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1746    {
1747        static int once;
1748        va_list argp, argq;
1749    
1750        va_start(argp, fmt);
1751    
1752        va_copy(argq, argp);
1753        if (!once) {
1754     log_time(NULL);
1755     log_message(NULL, "command line: %s\n", saved_command_line);
1756        }
1757        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1758        log_vmessage(NULL, fmt, argq);
1759    
1760        printEntry(entry, NULL);
1761        va_end(argq);
1762    
1763        if (!debug) {
1764     once = 1;
1765         va_end(argp);
1766     return;
1767        }
1768    
1769        if (okay) {
1770     va_end(argp);
1771     return;
1772        }
1773    
1774        if (!once)
1775     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1776        once = 1;
1777        fprintf(stderr, "DBG: Image entry failed: ");
1778        vfprintf(stderr, fmt, argp);
1779        printEntry(entry, stderr);
1780        va_end(argp);
1781    }
1782    
1783    #define beginswith(s, c) ((s) && (s)[0] == (c))
1784    
1785    static int endswith(const char *s, char c)
1786    {
1787     int slen;
1788    
1789     if (!s || !s[0])
1790     return 0;
1791     slen = strlen(s) - 1;
1792    
1793     return s[slen] == c;
1794    }
1795    
1796    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1797      int skipRemoved, int flags) {
1798        struct singleLine * line;
1799        char * fullName;
1800        int i;
1801        char * dev;
1802        char * rootspec;
1803        char * rootdev;
1804    
1805        if (skipRemoved && entry->skip) {
1806     notSuitablePrintf(entry, 0, "marked to skip\n");
1807     return 0;
1808        }
1809    
1810        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1811        if (!line) {
1812     notSuitablePrintf(entry, 0, "no line found\n");
1813     return 0;
1814        }
1815        if (line->numElements < 2) {
1816     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1817        line->numElements);
1818     return 0;
1819        }
1820    
1821        if (flags & GRUBBY_BADIMAGE_OKAY) {
1822        notSuitablePrintf(entry, 1, "\n");
1823        return 1;
1824        }
1825    
1826        fullName = alloca(strlen(bootPrefix) +
1827          strlen(line->elements[1].item) + 1);
1828        rootspec = getRootSpecifier(line->elements[1].item);
1829        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1830        int hasslash = endswith(bootPrefix, '/') ||
1831         beginswith(line->elements[1].item + rootspec_offset, '/');
1832        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1833                line->elements[1].item + rootspec_offset);
1834        if (access(fullName, R_OK)) {
1835     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1836     return 0;
1837        }
1838        for (i = 2; i < line->numElements; i++)
1839     if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1840        if (i < line->numElements) {
1841     dev = line->elements[i].item + 5;
1842      } else {      } else {
1843   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1844   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1845    
1846   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1847      dev = line->elements[1].item;      dev = line->elements[1].item;
1848   } else {   } else {
1849              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1850      /* 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.
1851      line = entry->lines;       */
1852        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1853    
1854              /* failed to find one */              /* failed to find one */
1855              if (!line) return 0;              if (!line) {
1856     notSuitablePrintf(entry, 0, "no line found\n");
1857     return 0;
1858                }
1859    
1860      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1861          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1862      if (i < line->numElements)      if (i < line->numElements)
1863          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1864      else {      else {
1865     notSuitablePrintf(entry, 0, "no root= entry found\n");
1866   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1867          return 0;          return 0;
1868              }              }
1869   }   }
1870      }      }
1871    
1872      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1873   dev += 6;      if (!getpathbyspec(dev)) {
1874            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1875   /* check which device has this label */          return 0;
1876   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1877   if (!dev) return 0;   dev = getpathbyspec(dev);
1878    
1879        rootdev = findDiskForRoot();
1880        if (!rootdev) {
1881            notSuitablePrintf(entry, 0, "can't find root device\n");
1882     return 0;
1883      }      }
1884    
1885      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1886   if (stat(dev, &sb))          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1887      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1888      } else {          free(rootdev);
1889   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1890   if (*end) return 0;      }
1891    
1892        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1893            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1894     getuuidbydev(rootdev), getuuidbydev(dev));
1895     free(rootdev);
1896            return 0;
1897      }      }
     stat("/", &sb2);  
1898    
1899      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1900        notSuitablePrintf(entry, 1, "\n");
1901    
1902      return 1;      return 1;
1903  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1941  struct singleEntry * findEntryByPath(str
1941   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1942   if (!entry) return NULL;   if (!entry) return NULL;
1943    
1944   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1945   if (!line) return NULL;   if (!line) return NULL;
1946    
1947   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1979  struct singleEntry * findEntryByPath(str
1979    
1980   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1981      prefix = "";      prefix = "";
1982      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1983      kernel += 6;      kernel += 6;
1984   }   }
1985    
1986   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1987      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1988    
1989        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1990    
1991      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1992                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1993          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
1994                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1995                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1996                      break;   else if (checkType & LT_KERNEL)
1997              }      ct = checkType | LT_KERNEL_EFI;
1998                 line = getLineByType(ct, line);
1999              /* have to check multiboot lines too */   if (!line)
2000              if (entry->multiboot) {      break;  /* not found in this entry */
2001                  while (line && line->type != LT_MBMODULE) line = line->next;  
2002                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
2003                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
2004                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
2005                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
2006                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
2007                          break;   kernel + strlen(prefix)))
2008                  }   break;
2009              }   }
2010     if(line->type == LT_MENUENTRY &&
2011     !strcmp(line->elements[1].item, kernel))
2012        break;
2013        }
2014    
2015      i++;      /* make sure this entry has a kernel identifier; this skips
2016         * non-Linux boot entries (could find netbsd etc, though, which is
2017         * unfortunate)
2018         */
2019        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
2020     break; /* found 'im! */
2021   }   }
2022    
2023   if (index) *index = i;   if (index) *index = i;
2024      }      }
2025    
2026      if (!entry) return NULL;      return entry;
2027    }
2028    
2029      /* make sure this entry has a kernel identifier; this skips non-Linux  struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2030         boot entries (could find netbsd etc, though, which is unfortunate) */        int * index) {
2031      line = entry->lines;      struct singleEntry * entry;
2032      while (line && line->type != LT_KERNEL) line = line->next;      struct singleLine * line;
2033      if (!line) {      int i;
2034   if (!index) index = &i;      char * newtitle;
2035   (*index)++;  
2036   return findEntryByPath(config, kernel, prefix, index);      for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2037     if (index && i < *index)
2038        continue;
2039     line = getLineByType(LT_TITLE, entry->lines);
2040     if (!line)
2041        line = getLineByType(LT_MENUENTRY, entry->lines);
2042     if (!line)
2043        continue;
2044     newtitle = grub2ExtractTitle(line);
2045     if (!newtitle)
2046        continue;
2047     if (!strcmp(title, newtitle))
2048        break;
2049      }      }
2050    
2051        if (!entry)
2052     return NULL;
2053    
2054        if (index)
2055     *index = i;
2056      return entry;      return entry;
2057  }  }
2058    
# Line 1147  struct singleEntry * findTemplate(struct Line 2078  struct singleEntry * findTemplate(struct
2078      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2079      int index;      int index;
2080    
2081      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2082     if (cfg->cfi->getEnv) {
2083        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2084        if (defTitle) {
2085     int index = 0;
2086     if (isnumber(defTitle)) {
2087        index = atoi(defTitle);
2088        entry = findEntryByIndex(cfg, index);
2089     } else {
2090        entry = findEntryByTitle(cfg, defTitle, &index);
2091     }
2092     if (entry)
2093        cfg->defaultImage = index;
2094        }
2095     }
2096        } else if (cfg->defaultImage > -1) {
2097   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2098   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2099      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1200  void markRemovedImage(struct grubConfig Line 2146  void markRemovedImage(struct grubConfig
2146        const char * prefix) {        const char * prefix) {
2147      struct singleEntry * entry;      struct singleEntry * entry;
2148    
2149      if (!image) return;      if (!image)
2150     return;
2151    
2152        /* check and see if we're removing the default image */
2153        if (isdigit(*image)) {
2154     entry = findEntryByPath(cfg, image, prefix, NULL);
2155     if(entry)
2156        entry->skip = 1;
2157     return;
2158        }
2159    
2160      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2161   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 2163  void markRemovedImage(struct grubConfig
2163    
2164  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2165       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2166       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2167      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2168      int i, j;      int i, j;
2169    
2170      if (newIsDefault) {      if (newIsDefault) {
2171   config->defaultImage = 0;   config->defaultImage = 0;
2172   return;   return;
2173        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2174     if (findEntryByIndex(config, index))
2175        config->defaultImage = index;
2176     else
2177        config->defaultImage = -1;
2178     return;
2179      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2180   i = 0;   i = 0;
2181   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 2188  void setDefaultImage(struct grubConfig *
2188    
2189      /* 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
2190         changes */         changes */
2191      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2192     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2193        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2194        return;        return;
2195    
# Line 1286  void displayEntry(struct singleEntry * e Line 2248  void displayEntry(struct singleEntry * e
2248      char * root = NULL;      char * root = NULL;
2249      int i;      int i;
2250    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2251      printf("index=%d\n", index);      printf("index=%d\n", index);
2252    
2253      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
2254        if (!line) {
2255            printf("non linux entry\n");
2256            return;
2257        }
2258    
2259        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2260     printf("kernel=%s\n", line->elements[1].item);
2261        else
2262     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2263    
2264      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2265   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2276  void displayEntry(struct singleEntry * e
2276   }   }
2277   printf("\"\n");   printf("\"\n");
2278      } else {      } else {
2279   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2280   if (line) {   if (line) {
2281      char * s;      char * s;
2282    
# Line 1334  void displayEntry(struct singleEntry * e Line 2300  void displayEntry(struct singleEntry * e
2300      }      }
2301    
2302      if (!root) {      if (!root) {
2303   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2304   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2305      root=line->elements[1].item;      root=line->elements[1].item;
2306      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2315  void displayEntry(struct singleEntry * e
2315   printf("root=%s\n", s);   printf("root=%s\n", s);
2316      }      }
2317    
2318      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2319    
2320      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2321   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2322        printf("initrd=");
2323     else
2324        printf("initrd=%s", prefix);
2325    
2326   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2327      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2328   printf("\n");   printf("\n");
2329      }      }
2330    
2331        line = getLineByType(LT_TITLE, entry->lines);
2332        if (line) {
2333     printf("title=%s\n", line->elements[1].item);
2334        } else {
2335     char * title;
2336     line = getLineByType(LT_MENUENTRY, entry->lines);
2337     title = grub2ExtractTitle(line);
2338     if (title)
2339        printf("title=%s\n", title);
2340        }
2341    }
2342    
2343    int isSuseSystem(void) {
2344        const char * path;
2345        const static char default_path[] = "/etc/SuSE-release";
2346    
2347        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2348     path = default_path;
2349    
2350        if (!access(path, R_OK))
2351     return 1;
2352        return 0;
2353    }
2354    
2355    int isSuseGrubConf(const char * path) {
2356        FILE * grubConf;
2357        char * line = NULL;
2358        size_t len = 0, res = 0;
2359    
2360        grubConf = fopen(path, "r");
2361        if (!grubConf) {
2362            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2363     return 0;
2364        }
2365    
2366        while ((res = getline(&line, &len, grubConf)) != -1) {
2367     if (!strncmp(line, "setup", 5)) {
2368        fclose(grubConf);
2369        free(line);
2370        return 1;
2371     }
2372        }
2373    
2374        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2375          path);
2376    
2377        fclose(grubConf);
2378        free(line);
2379        return 0;
2380    }
2381    
2382    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2383        FILE * grubConf;
2384        char * line = NULL;
2385        size_t res = 0, len = 0;
2386    
2387        if (!path) return 1;
2388        if (!lbaPtr) return 1;
2389    
2390        grubConf = fopen(path, "r");
2391        if (!grubConf) return 1;
2392    
2393        while ((res = getline(&line, &len, grubConf)) != -1) {
2394     if (line[res - 1] == '\n')
2395        line[res - 1] = '\0';
2396     else if (len > res)
2397        line[res] = '\0';
2398     else {
2399        line = realloc(line, res + 1);
2400        line[res] = '\0';
2401     }
2402    
2403     if (!strncmp(line, "setup", 5)) {
2404        if (strstr(line, "--force-lba")) {
2405            *lbaPtr = 1;
2406        } else {
2407            *lbaPtr = 0;
2408        }
2409        dbgPrintf("lba: %i\n", *lbaPtr);
2410        break;
2411     }
2412        }
2413    
2414        free(line);
2415        fclose(grubConf);
2416        return 0;
2417    }
2418    
2419    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2420        FILE * grubConf;
2421        char * line = NULL;
2422        size_t res = 0, len = 0;
2423        char * lastParamPtr = NULL;
2424        char * secLastParamPtr = NULL;
2425        char installDeviceNumber = '\0';
2426        char * bounds = NULL;
2427    
2428        if (!path) return 1;
2429        if (!devicePtr) return 1;
2430    
2431        grubConf = fopen(path, "r");
2432        if (!grubConf) return 1;
2433    
2434        while ((res = getline(&line, &len, grubConf)) != -1) {
2435     if (strncmp(line, "setup", 5))
2436        continue;
2437    
2438     if (line[res - 1] == '\n')
2439        line[res - 1] = '\0';
2440     else if (len > res)
2441        line[res] = '\0';
2442     else {
2443        line = realloc(line, res + 1);
2444        line[res] = '\0';
2445     }
2446    
2447     lastParamPtr = bounds = line + res;
2448    
2449     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2450     while (!isspace(*lastParamPtr))
2451        lastParamPtr--;
2452     lastParamPtr++;
2453    
2454     secLastParamPtr = lastParamPtr - 2;
2455     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2456    
2457     if (lastParamPtr + 3 > bounds) {
2458        dbgPrintf("lastParamPtr going over boundary");
2459        fclose(grubConf);
2460        free(line);
2461        return 1;
2462     }
2463     if (!strncmp(lastParamPtr, "(hd", 3))
2464        lastParamPtr += 3;
2465     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2466    
2467     /*
2468     * Second last parameter will decide wether last parameter is
2469     * an IMAGE_DEVICE or INSTALL_DEVICE
2470     */
2471     while (!isspace(*secLastParamPtr))
2472        secLastParamPtr--;
2473     secLastParamPtr++;
2474    
2475     if (secLastParamPtr + 3 > bounds) {
2476        dbgPrintf("secLastParamPtr going over boundary");
2477        fclose(grubConf);
2478        free(line);
2479        return 1;
2480     }
2481     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2482     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2483        secLastParamPtr += 3;
2484        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2485        installDeviceNumber = *secLastParamPtr;
2486     } else {
2487        installDeviceNumber = *lastParamPtr;
2488     }
2489    
2490     *devicePtr = malloc(6);
2491     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2492     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2493     fclose(grubConf);
2494     free(line);
2495     return 0;
2496        }
2497    
2498        free(line);
2499        fclose(grubConf);
2500        return 1;
2501    }
2502    
2503    int grubGetBootFromDeviceMap(const char * device,
2504         char ** bootPtr) {
2505        FILE * deviceMap;
2506        char * line = NULL;
2507        size_t res = 0, len = 0;
2508        char * devicePtr;
2509        char * bounds = NULL;
2510        const char * path;
2511        const static char default_path[] = "/boot/grub/device.map";
2512    
2513        if (!device) return 1;
2514        if (!bootPtr) return 1;
2515    
2516        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2517     path = default_path;
2518    
2519        dbgPrintf("opening grub device.map file from: %s\n", path);
2520        deviceMap = fopen(path, "r");
2521        if (!deviceMap)
2522     return 1;
2523    
2524        while ((res = getline(&line, &len, deviceMap)) != -1) {
2525            if (!strncmp(line, "#", 1))
2526        continue;
2527    
2528     if (line[res - 1] == '\n')
2529        line[res - 1] = '\0';
2530     else if (len > res)
2531        line[res] = '\0';
2532     else {
2533        line = realloc(line, res + 1);
2534        line[res] = '\0';
2535     }
2536    
2537     devicePtr = line;
2538     bounds = line + res;
2539    
2540     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2541        devicePtr++;
2542     dbgPrintf("device: %s\n", devicePtr);
2543    
2544     if (!strncmp(devicePtr, device, strlen(device))) {
2545        devicePtr += strlen(device);
2546        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2547            devicePtr++;
2548    
2549        *bootPtr = strdup(devicePtr);
2550        break;
2551     }
2552        }
2553    
2554        free(line);
2555        fclose(deviceMap);
2556        return 0;
2557    }
2558    
2559    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2560        char * grubDevice;
2561    
2562        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2563     dbgPrintf("error looking for grub installation device\n");
2564        else
2565     dbgPrintf("grubby installation device: %s\n", grubDevice);
2566    
2567        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2568     dbgPrintf("error looking for grub boot device\n");
2569        else
2570     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2571    
2572        free(grubDevice);
2573        return 0;
2574    }
2575    
2576    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2577        /*
2578         * This SuSE grub configuration file at this location is not your average
2579         * grub configuration file, but instead the grub commands used to setup
2580         * grub on that system.
2581         */
2582        const char * path;
2583        const static char default_path[] = "/etc/grub.conf";
2584    
2585        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2586     path = default_path;
2587    
2588        if (!isSuseGrubConf(path)) return 1;
2589    
2590        if (lbaPtr) {
2591            *lbaPtr = 0;
2592            if (suseGrubConfGetLba(path, lbaPtr))
2593                return 1;
2594        }
2595    
2596        if (bootPtr) {
2597            *bootPtr = NULL;
2598            suseGrubConfGetBoot(path, bootPtr);
2599        }
2600    
2601        return 0;
2602  }  }
2603    
2604  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2608  int parseSysconfigGrub(int * lbaPtr, cha
2608      char * start;      char * start;
2609      char * param;      char * param;
2610    
2611      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2612      if (!in) return 1;      if (!in) return 1;
2613    
2614      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2649  int parseSysconfigGrub(int * lbaPtr, cha
2649  }  }
2650    
2651  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2652      char * boot;      char * boot = NULL;
2653      int lba;      int lba;
2654    
2655      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2656   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2657   if (boot) printf("boot=%s\n", boot);      free(boot);
2658        return;
2659     }
2660        } else {
2661            if (parseSysconfigGrub(&lba, &boot)) {
2662        free(boot);
2663        return;
2664     }
2665        }
2666    
2667        if (lba) printf("lba\n");
2668        if (boot) {
2669     printf("boot=%s\n", boot);
2670     free(boot);
2671      }      }
2672  }  }
2673    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2683  int displayInfo(struct grubConfig * conf
2683   return 1;   return 1;
2684      }      }
2685    
2686      /* 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
2687         be a better way */         be a better way */
2688      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2689   dumpSysconfigGrub();   dumpSysconfigGrub();
2690      } else {      } else {
2691   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2692   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2693      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2694   }   }
2695    
2696   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2697   if (line) printf("lba\n");   if (line) printf("lba\n");
2698      }      }
2699    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2708  int displayInfo(struct grubConfig * conf
2708      return 0;      return 0;
2709  }  }
2710    
2711    struct singleLine * addLineTmpl(struct singleEntry * entry,
2712     struct singleLine * tmplLine,
2713     struct singleLine * prevLine,
2714     const char * val,
2715     struct configFileInfo * cfi)
2716    {
2717        struct singleLine * newLine = lineDup(tmplLine);
2718    
2719        if (isEfi && cfi == &grub2ConfigType) {
2720     enum lineType_e old = newLine->type;
2721     newLine->type = preferredLineType(newLine->type, cfi);
2722     if (old != newLine->type)
2723        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2724        }
2725    
2726        if (val) {
2727     /* override the inherited value with our own.
2728     * This is a little weak because it only applies to elements[1]
2729     */
2730     if (newLine->numElements > 1)
2731        removeElement(newLine, 1);
2732     insertElement(newLine, val, 1, cfi);
2733    
2734     /* but try to keep the rootspec from the template... sigh */
2735     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2736        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2737        if (rootspec != NULL) {
2738     free(newLine->elements[1].item);
2739     newLine->elements[1].item =
2740        sdupprintf("%s%s", rootspec, val);
2741        }
2742     }
2743        }
2744    
2745        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2746          newLine->elements[0].item : "");
2747    
2748        if (!entry->lines) {
2749     /* first one on the list */
2750     entry->lines = newLine;
2751        } else if (prevLine) {
2752     /* add after prevLine */
2753     newLine->next = prevLine->next;
2754     prevLine->next = newLine;
2755        }
2756    
2757        return newLine;
2758    }
2759    
2760  /* val may be NULL */  /* val may be NULL */
2761  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2762       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2763       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2764       char * val) {       const char * val) {
2765      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2766      int i;      struct keywordTypes * kw;
2767        struct singleLine tmpl;
2768    
2769      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2770   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2771      if (type != LT_TITLE || !cfi->titleBracketed)       */
2772          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2773     /* we're doing a bracketed title (zipl) */
2774     tmpl.type = type;
2775     tmpl.numElements = 1;
2776     tmpl.elements = alloca(sizeof(*tmpl.elements));
2777     tmpl.elements[0].item = alloca(strlen(val)+3);
2778     sprintf(tmpl.elements[0].item, "[%s]", val);
2779     tmpl.elements[0].indent = "";
2780     val = NULL;
2781        } else if (type == LT_MENUENTRY) {
2782     char *lineend = "--class gnu-linux --class gnu --class os {";
2783     if (!val) {
2784        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2785        abort();
2786     }
2787     kw = getKeywordByType(type, cfi);
2788     if (!kw) {
2789        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2790        abort();
2791     }
2792     tmpl.indent = "";
2793     tmpl.type = type;
2794     tmpl.numElements = 3;
2795     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2796     tmpl.elements[0].item = kw->key;
2797     tmpl.elements[0].indent = alloca(2);
2798     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2799     tmpl.elements[1].item = (char *)val;
2800     tmpl.elements[1].indent = alloca(2);
2801     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2802     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2803     strcpy(tmpl.elements[2].item, lineend);
2804     tmpl.elements[2].indent = "";
2805        } else {
2806     kw = getKeywordByType(type, cfi);
2807     if (!kw) {
2808        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2809        abort();
2810     }
2811     tmpl.type = type;
2812     tmpl.numElements = val ? 2 : 1;
2813     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2814     tmpl.elements[0].item = kw->key;
2815     tmpl.elements[0].indent = alloca(2);
2816     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2817     if (val) {
2818        tmpl.elements[1].item = (char *)val;
2819        tmpl.elements[1].indent = "";
2820     }
2821        }
2822    
2823      /* 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
2824         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2825         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
2826         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2827         differently from the rest) */         differently from the rest) */
2828      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2829   line = entry->lines;   if (line->numElements) prev = line;
2830   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2831   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;  
2832      }      }
2833    
2834      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2835          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2836          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2837          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2838          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2839          line->elements[0].indent = malloc(2);   else
2840          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2841          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2842             if (menuEntry)
2843          if (val) {      tmpl.indent = "\t";
2844              line->elements[1].item = val;   else if (prev == entry->lines)
2845              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2846          }   else
2847      } 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("");  
2848      }      }
2849    
2850      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2851  }  }
2852    
2853  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1550  void removeLine(struct singleEntry * ent Line 2869  void removeLine(struct singleEntry * ent
2869   prev->next = line->next;   prev->next = line->next;
2870      }      }
2871    
2872      free(line);      free(line);
2873    }
2874    
2875    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2876    {
2877        struct singleLine newLine = {
2878     .indent = tmplLine->indent,
2879     .type = tmplLine->type,
2880     .next = tmplLine->next,
2881        };
2882        int firstQuotedItem = -1;
2883        int quoteLen = 0;
2884        int j;
2885        int element = 0;
2886        char *c;
2887    
2888        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2889        strcpy(c, tmplLine->elements[0].item);
2890        insertElement(&newLine, c, element++, cfi);
2891        free(c);
2892        c = NULL;
2893    
2894        for (j = 1; j < tmplLine->numElements; j++) {
2895     if (firstQuotedItem == -1) {
2896        quoteLen += strlen(tmplLine->elements[j].item);
2897        
2898        if (isquote(tmplLine->elements[j].item[0])) {
2899     firstQuotedItem = j;
2900            quoteLen += strlen(tmplLine->elements[j].indent);
2901        } else {
2902     c = malloc(quoteLen + 1);
2903     strcpy(c, tmplLine->elements[j].item);
2904     insertElement(&newLine, c, element++, cfi);
2905     free(c);
2906     quoteLen = 0;
2907        }
2908     } else {
2909        int itemlen = strlen(tmplLine->elements[j].item);
2910        quoteLen += itemlen;
2911        quoteLen += strlen(tmplLine->elements[j].indent);
2912        
2913        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2914     c = malloc(quoteLen + 1);
2915     c[0] = '\0';
2916     for (int i = firstQuotedItem; i < j+1; i++) {
2917        strcat(c, tmplLine->elements[i].item);
2918        strcat(c, tmplLine->elements[i].indent);
2919     }
2920     insertElement(&newLine, c, element++, cfi);
2921     free(c);
2922    
2923     firstQuotedItem = -1;
2924     quoteLen = 0;
2925        }
2926     }
2927        }
2928        while (tmplLine->numElements)
2929     removeElement(tmplLine, 0);
2930        if (tmplLine->elements)
2931     free(tmplLine->elements);
2932    
2933        tmplLine->numElements = newLine.numElements;
2934        tmplLine->elements = newLine.elements;
2935    }
2936    
2937    static void insertElement(struct singleLine * line,
2938      const char * item, int insertHere,
2939      struct configFileInfo * cfi)
2940    {
2941        struct keywordTypes * kw;
2942        char indent[2] = "";
2943    
2944        /* sanity check */
2945        if (insertHere > line->numElements) {
2946     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2947      insertHere, line->numElements);
2948     insertHere = line->numElements;
2949        }
2950    
2951        line->elements = realloc(line->elements, (line->numElements + 1) *
2952         sizeof(*line->elements));
2953        memmove(&line->elements[insertHere+1],
2954        &line->elements[insertHere],
2955        (line->numElements - insertHere) *
2956        sizeof(*line->elements));
2957        line->elements[insertHere].item = strdup(item);
2958    
2959        kw = getKeywordByType(line->type, cfi);
2960    
2961        if (line->numElements == 0) {
2962     indent[0] = '\0';
2963        } else if (insertHere == 0) {
2964     indent[0] = kw->nextChar;
2965        } else if (kw->separatorChar != '\0') {
2966     indent[0] = kw->separatorChar;
2967        } else {
2968     indent[0] = ' ';
2969        }
2970    
2971        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2972     /* move the end-of-line forward */
2973     line->elements[insertHere].indent =
2974        line->elements[insertHere-1].indent;
2975     line->elements[insertHere-1].indent = strdup(indent);
2976        } else {
2977     line->elements[insertHere].indent = strdup(indent);
2978        }
2979    
2980        line->numElements++;
2981    
2982        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2983          line->elements[0].item,
2984          line->elements[insertHere].item,
2985          line->elements[insertHere].indent,
2986          insertHere);
2987    }
2988    
2989    static void removeElement(struct singleLine * line, int removeHere) {
2990        int i;
2991    
2992        /* sanity check */
2993        if (removeHere >= line->numElements) return;
2994    
2995        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2996          removeHere, line->elements[removeHere].item);
2997    
2998        free(line->elements[removeHere].item);
2999    
3000        if (removeHere > 1) {
3001     /* previous argument gets this argument's post-indentation */
3002     free(line->elements[removeHere-1].indent);
3003     line->elements[removeHere-1].indent =
3004        line->elements[removeHere].indent;
3005        } else {
3006     free(line->elements[removeHere].indent);
3007        }
3008    
3009        /* now collapse the array, but don't bother to realloc smaller */
3010        for (i = removeHere; i < line->numElements - 1; i++)
3011     line->elements[i] = line->elements[i + 1];
3012    
3013        line->numElements--;
3014  }  }
3015    
3016  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
# Line 1575  int updateActualImage(struct grubConfig Line 3035  int updateActualImage(struct grubConfig
3035      struct singleEntry * entry;      struct singleEntry * entry;
3036      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
3037      int index = 0;      int index = 0;
3038      int i, j, k;      int i, k;
3039      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
3040      const char ** arg;      const char ** arg;
3041      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
3042      int firstElement;      int firstElement;
3043      int *usedElements, *usedArgs;      int *usedElements;
3044        int doreplace;
3045    
3046      if (!image) return 0;      if (!image) return 0;
3047    
# Line 1609  int updateActualImage(struct grubConfig Line 3068  int updateActualImage(struct grubConfig
3068   }   }
3069      }      }
3070    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
3071    
3072      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
3073   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
3074    
3075      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3076   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
3077    
3078      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
3079    
3080      k = 0;   if (multibootArgs && !entry->multiboot)
3081      for (arg = newArgs; *arg; arg++)      continue;
3082          k++;  
3083      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
3084     * LT_KERNELARGS, use that.  Otherwise use
3085     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
3086     */
3087     if (useKernelArgs) {
3088        line = getLineByType(LT_KERNELARGS, entry->lines);
3089        if (!line) {
3090     /* no LT_KERNELARGS, need to add it */
3091     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
3092           cfg->secondaryIndent, NULL);
3093        }
3094        firstElement = 1;
3095    
3096      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
3097   index++;      line = getLineByType(LT_HYPER, entry->lines);
3098        if (!line) {
3099     /* a multiboot entry without LT_HYPER? */
3100     continue;
3101        }
3102        firstElement = 2;
3103    
3104   line = entry->lines;   } else {
3105   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
3106   if (!line) continue;      if (!line) {
3107   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3108     continue;
3109          if (entry->multiboot && !multibootArgs) {      }
3110              /* 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;  
3111   }   }
3112    
3113   if (!line && useKernelArgs) {   /* handle the elilo case which does:
3114      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
3115      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
3116     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
3117        /* this is a multiboot entry, make sure there's
3118         * -- on the args line
3119         */
3120        for (i = firstElement; i < line->numElements; i++) {
3121     if (!strcmp(line->elements[i].item, "--"))
3122        break;
3123        }
3124        if (i == line->numElements) {
3125     /* assume all existing args are kernel args,
3126     * prepend -- to make it official
3127     */
3128     insertElement(line, "--", firstElement, cfg->cfi);
3129     i = firstElement;
3130        }
3131        if (!multibootArgs) {
3132     /* kernel args start after the -- */
3133     firstElement = i + 1;
3134        }
3135     } else if (cfg->cfi->mbConcatArgs) {
3136        /* this is a non-multiboot entry, remove hyper args */
3137        for (i = firstElement; i < line->numElements; i++) {
3138     if (!strcmp(line->elements[i].item, "--"))
3139        break;
3140        }
3141        if (i < line->numElements) {
3142     /* remove args up to -- */
3143     while (strcmp(line->elements[firstElement].item, "--"))
3144        removeElement(line, firstElement);
3145     /* remove -- */
3146     removeElement(line, firstElement);
3147        }
3148   }   }
3149    
3150          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
3151    
3152          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
3153   for (arg = newArgs; *arg; arg++) {  
3154              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
3155      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
3156     if (multibootArgs && cfg->cfi->mbConcatArgs &&
3157        !strcmp(line->elements[i].item, "--"))
3158     {
3159        /* reached the end of hyper args, insert here */
3160        doreplace = 0;
3161        break;  
3162     }
3163                  if (usedElements[i])                  if (usedElements[i])
3164                      continue;                      continue;
3165   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3166                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3167      break;      break;
3168                  }                  }
3169              }              }
     chptr = strchr(*arg, '=');  
3170    
3171      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
3172   /* replace */   /* direct replacement */
3173   free(line->elements[i].item);   free(line->elements[i].item);
3174   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("");  
  }  
3175    
3176   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
3177   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
3178      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
3179   /* append */   if (rootLine) {
3180   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
3181   (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(" ");  
3182   } else {   } else {
3183      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
3184         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
3185   }   }
3186        }
3187    
3188   line->numElements++;      else {
3189     /* insert/append */
3190     insertElement(line, *arg, i, cfg->cfi);
3191     usedElements = realloc(usedElements, line->numElements *
3192           sizeof(*usedElements));
3193     memmove(&usedElements[i + 1], &usedElements[i],
3194     line->numElements - i - 1);
3195     usedElements[i] = 1;
3196    
3197   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
3198     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
3199     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
3200   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
3201      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
3202      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
3203   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
3204   }   }
3205      }      }
             k++;  
3206   }   }
3207    
3208          free(usedElements);          free(usedElements);
3209    
  /* 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? */  
3210   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
3211      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
3212   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
3213        !strcmp(line->elements[i].item, "--"))
3214        /* reached the end of hyper args, stop here */
3215        break;
3216     if (!argMatch(line->elements[i].item, *arg)) {
3217        removeElement(line, i);
3218      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;  
3219   }   }
3220        }
3221   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
3222        if (useRoot && !strncmp(*arg, "root=", 5)) {
3223   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3224      line->elements[j - 1] = line->elements[j];   if (rootLine)
3225        removeLine(entry, rootLine);
  line->numElements--;  
3226      }      }
3227   }   }
3228    
# Line 1760  int updateActualImage(struct grubConfig Line 3233  int updateActualImage(struct grubConfig
3233   }   }
3234      }      }
3235    
     free(usedArgs);  
3236      free(newArgs);      free(newArgs);
3237      free(oldArgs);      free(oldArgs);
3238    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3258  int updateImage(struct grubConfig * cfg,
3258      return rc;      return rc;
3259  }  }
3260    
3261    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3262     const char * image, const char * prefix, const char * initrd) {
3263        struct singleEntry * entry;
3264        struct singleLine * line, * kernelLine, *endLine = NULL;
3265        int index = 0;
3266    
3267        if (!image) return 0;
3268    
3269        for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) {
3270            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3271            if (!kernelLine) continue;
3272    
3273            if (prefix) {
3274                int prefixLen = strlen(prefix);
3275                if (!strncmp(initrd, prefix, prefixLen))
3276                    initrd += prefixLen;
3277            }
3278     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3279     if (endLine)
3280        removeLine(entry, endLine);
3281            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3282     kernelLine->indent, initrd);
3283            if (!line)
3284        return 1;
3285     if (endLine) {
3286        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3287                if (!line)
3288     return 1;
3289     }
3290    
3291            break;
3292        }
3293    
3294        return 0;
3295    }
3296    
3297    int updateInitrd(struct grubConfig * cfg, const char * image,
3298                     const char * prefix, const char * initrd) {
3299        struct singleEntry * entry;
3300        struct singleLine * line, * kernelLine, *endLine = NULL;
3301        int index = 0;
3302    
3303        if (!image) return 0;
3304    
3305        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3306            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3307            if (!kernelLine) continue;
3308    
3309            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3310            if (line)
3311                removeLine(entry, line);
3312            if (prefix) {
3313                int prefixLen = strlen(prefix);
3314                if (!strncmp(initrd, prefix, prefixLen))
3315                    initrd += prefixLen;
3316            }
3317     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3318     if (endLine)
3319        removeLine(entry, endLine);
3320            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3321     kernelLine->indent, initrd);
3322            if (!line)
3323        return 1;
3324     if (endLine) {
3325        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3326                if (!line)
3327     return 1;
3328     }
3329    
3330            break;
3331        }
3332    
3333        return 0;
3334    }
3335    
3336  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3337      int fd;      int fd;
3338      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3356  int checkDeviceBootloader(const char * d
3356      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3357   return 0;   return 0;
3358    
3359      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3360   offset = boot[2] + 2;   offset = boot[2] + 2;
3361      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3362   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3363      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3364   offset = boot[1] + 2;        offset = boot[1] + 2;
3365            /*
3366     * it looks like grub, when copying stage1 into the mbr, patches stage1
3367     * right after the JMP location, replacing other instructions such as
3368     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3369     * different bytes.
3370     */
3371          if ((bootSect[offset + 1] == NOOP_OPCODE)
3372      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3373     offset = offset + 3;
3374          }
3375      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3376   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3377      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3513  int checkForLilo(struct grubConfig * con
3513      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3514  }  }
3515    
3516    int checkForGrub2(struct grubConfig * config) {
3517        if (!access("/etc/grub.d/", R_OK))
3518     return 2;
3519    
3520        return 1;
3521    }
3522    
3523  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3524      int fd;      int fd;
3525      unsigned char bootSect[512];      unsigned char bootSect[512];
3526      char * boot;      char * boot;
3527        int onSuse = isSuseSystem();
3528    
3529      if (parseSysconfigGrub(NULL, &boot))  
3530   return 0;      if (onSuse) {
3531     if (parseSuseGrubConf(NULL, &boot))
3532        return 0;
3533        } else {
3534     if (parseSysconfigGrub(NULL, &boot))
3535        return 0;
3536        }
3537    
3538      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3539      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3547  int checkForGrub(struct grubConfig * con
3547      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3548   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3549   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3550     close(fd);
3551     return 1;
3552        }
3553        close(fd);
3554    
3555        /* The more elaborate checks do not work on SuSE. The checks done
3556         * seem to be reasonble (at least for now), so just return success
3557         */
3558        if (onSuse)
3559     return 2;
3560    
3561        return checkDeviceBootloader(boot, bootSect);
3562    }
3563    
3564    int checkForExtLinux(struct grubConfig * config) {
3565        int fd;
3566        unsigned char bootSect[512];
3567        char * boot;
3568        char executable[] = "/boot/extlinux/extlinux";
3569    
3570        printf("entered: checkForExtLinux()\n");
3571    
3572        if (parseSysconfigGrub(NULL, &boot))
3573     return 0;
3574    
3575        /* assume grub is not installed -- not an error condition */
3576        if (!boot)
3577     return 0;
3578    
3579        fd = open(executable, O_RDONLY);
3580        if (fd < 0)
3581     /* this doesn't exist if grub hasn't been installed */
3582     return 0;
3583    
3584        if (read(fd, bootSect, 512) != 512) {
3585     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3586     executable, strerror(errno));
3587   return 1;   return 1;
3588      }      }
3589      close(fd);      close(fd);
# Line 1983  int checkForGrub(struct grubConfig * con Line 3591  int checkForGrub(struct grubConfig * con
3591      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3592  }  }
3593    
3594    int checkForYaboot(struct grubConfig * config) {
3595        /*
3596         * This is a simplistic check that we consider good enough for own puporses
3597         *
3598         * If we were to properly check if yaboot is *installed* we'd need to:
3599         * 1) get the system boot device (LT_BOOT)
3600         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3601         *    the content on the boot device
3602         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3603         * 4) check again if binary and boot device contents match
3604         */
3605        if (!access("/etc/yaboot.conf", R_OK))
3606     return 2;
3607    
3608        return 1;
3609    }
3610    
3611    int checkForElilo(struct grubConfig * config) {
3612        if (!access("/etc/elilo.conf", R_OK))
3613     return 2;
3614    
3615        return 1;
3616    }
3617    
3618  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3619      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3620    
# Line 1994  static char * getRootSpecifier(char * st Line 3626  static char * getRootSpecifier(char * st
3626      return rootspec;      return rootspec;
3627  }  }
3628    
3629    static char * getInitrdVal(struct grubConfig * config,
3630       const char * prefix, struct singleLine *tmplLine,
3631       const char * newKernelInitrd,
3632       const char ** extraInitrds, int extraInitrdCount)
3633    {
3634        char *initrdVal, *end;
3635        int i;
3636        size_t totalSize;
3637        size_t prefixLen;
3638        char separatorChar;
3639    
3640        prefixLen = strlen(prefix);
3641        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3642    
3643        for (i = 0; i < extraInitrdCount; i++) {
3644     totalSize += sizeof(separatorChar);
3645     totalSize += strlen(extraInitrds[i]) - prefixLen;
3646        }
3647    
3648        initrdVal = end = malloc(totalSize);
3649    
3650        end = stpcpy (end, newKernelInitrd + prefixLen);
3651    
3652        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3653        for (i = 0; i < extraInitrdCount; i++) {
3654     const char *extraInitrd;
3655     int j;
3656    
3657     extraInitrd = extraInitrds[i] + prefixLen;
3658     /* Don't add entries that are already there */
3659     if (tmplLine != NULL) {
3660        for (j = 2; j < tmplLine->numElements; j++)
3661     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3662        break;
3663    
3664        if (j != tmplLine->numElements)
3665     continue;
3666     }
3667    
3668     *end++ = separatorChar;
3669     end = stpcpy(end, extraInitrd);
3670        }
3671    
3672        return initrdVal;
3673    }
3674    
3675  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3676           const char * prefix,           const char * prefix,
3677   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3678   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3679                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3680                     const char * newMBKernel, const char * newMBKernelArgs) {
3681      struct singleEntry * new;      struct singleEntry * new;
3682      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3683      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3684      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3685    
3686      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3687    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3711  int addNewKernel(struct grubConfig * con
3711      config->entries = new;      config->entries = new;
3712    
3713      /* copy/update from the template */      /* copy/update from the template */
3714      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3715        if (newKernelInitrd)
3716     needs |= NEED_INITRD;
3717      if (newMBKernel) {      if (newMBKernel) {
3718          needs |= KERNEL_MB;          needs |= NEED_MB;
3719          new->multiboot = 1;          new->multiboot = 1;
3720      }      }
3721    
3722      if (template) {      if (template) {
3723   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3724      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3725      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3726   indent = tmplLine->indent;   {
3727        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3728    
3729      /* skip comments */      /* skip comments */
3730      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3731      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3732      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3733    
3734      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3735      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3736        /* it's not a multiboot template and this is the kernel
3737              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3738                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3739                  struct singleLine *l;       */
3740                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3741     /* insert the hypervisor first */
3742                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3743                                    config->secondaryIndent,    tmplLine->indent,
3744                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3745                     /* set up for adding the kernel line */
3746                  tmplLine = lastLine;   free(tmplLine->indent);
3747                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3748                      new->lines = l;   needs &= ~NEED_MB;
3749                  } else {      }
3750                      newLine->next = l;      if (needs & NEED_KERNEL) {
3751                      newLine = l;   /* use addLineTmpl to preserve line elements,
3752                  }   * otherwise we could just call addLine.  Unfortunately
3753                  continue;   * this means making some changes to the template
3754              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3755                         template->multiboot && !new->multiboot) {   * change below.
3756                  continue; /* don't need multiboot kernel here */   */
3757              }   struct keywordTypes * mbm_kw =
3758        getKeywordByType(LT_MBMODULE, config->cfi);
3759      if (!new->lines) {   if (mbm_kw) {
3760   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3761   new->lines = newLine;      free(tmplLine->elements[0].item);
3762      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3763   newLine->next = malloc(sizeof(*newLine));   }
3764   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3765      }        newKernelPath + strlen(prefix), config->cfi);
3766     needs &= ~NEED_KERNEL;
3767        }
3768        if (needs & NEED_MB) { /* !mbHyperFirst */
3769     newLine = addLine(new, config->cfi, LT_HYPER,
3770      config->secondaryIndent,
3771      newMBKernel + strlen(prefix));
3772     needs &= ~NEED_MB;
3773        }
3774     } else if (needs & NEED_KERNEL) {
3775        newLine = addLineTmpl(new, tmplLine, newLine,
3776      newKernelPath + strlen(prefix), config->cfi);
3777        needs &= ~NEED_KERNEL;
3778     }
3779    
3780        } else if (tmplLine->type == LT_HYPER &&
3781           tmplLine->numElements >= 2) {
3782     if (needs & NEED_MB) {
3783        newLine = addLineTmpl(new, tmplLine, newLine,
3784      newMBKernel + strlen(prefix), config->cfi);
3785        needs &= ~NEED_MB;
3786     }
3787    
3788      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3789      newLine->next = NULL;         tmplLine->numElements >= 2) {
3790      newLine->type = tmplLine->type;   if (new->multiboot) {
3791      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3792      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3793      newLine->numElements);        newKernelPath +
3794      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3795   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3796   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3797   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3798      }   char *initrdVal;
3799     initrdVal = getInitrdVal(config, prefix, tmplLine,
3800              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3801      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3802                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3803                  if (!template->multiboot) {        initrdVal, config->cfi);
3804                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3805                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3806                  } else {      }
3807                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3808                      repl = newMBKernel;      /* template is multi but new is not,
3809                  }       * insert the kernel in the first module slot
3810                  if (new->multiboot && !template->multiboot) {       */
3811                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3812                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3813                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3814                  }   strdup(getKeywordByType(tmplLine->type,
3815   free(newLine->elements[1].item);   config->cfi)->key);
3816                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3817                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3818                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3819                                                             rootspec,      needs &= ~NEED_KERNEL;
3820                                                             repl +   } else if (needs & NEED_INITRD) {
3821                                                             strlen(prefix));      char *initrdVal;
3822                  } else {      /* template is multi but new is not,
3823                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3824                                                         strlen(prefix));       */
3825                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3826              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3827                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3828                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3829                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3830                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3831                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3832                      newLine->type = LT_KERNEL;      free(initrdVal);
3833                  }      needs &= ~NEED_INITRD;
3834   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;  
3835    
3836   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3837      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3838      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3839        config->cfi->mbInitRdIsModule) {
3840        /* make sure we don't insert the module initrd
3841         * before the module kernel... if we don't do it here,
3842         * it will be inserted following the template.
3843         */
3844        if (!needs & NEED_KERNEL) {
3845     char *initrdVal;
3846    
3847     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3848     newLine = addLine(new, config->cfi, LT_MBMODULE,
3849      config->secondaryIndent,
3850      initrdVal);
3851     free(initrdVal);
3852     needs &= ~NEED_INITRD;
3853        }
3854     } else if (needs & NEED_INITRD) {
3855        char *initrdVal;
3856        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3857        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3858        free(initrdVal);
3859        needs &= ~NEED_INITRD;
3860   }   }
3861    
3862   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3863   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3864   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3865     char *nkt = malloc(strlen(newKernelTitle)+3);
3866     strcpy(nkt, "'");
3867     strcat(nkt, newKernelTitle);
3868     strcat(nkt, "'");
3869     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3870     free(nkt);
3871     needs &= ~NEED_TITLE;
3872      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3873                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3874                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3875                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3876                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3877                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3878                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3879                                             newLine->numElements);     config->cfi->titleBracketed) {
3880        /* addLineTmpl doesn't handle titleBracketed */
3881                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3882                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3883                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3884                  newLine->numElements = 1;   }
3885              }      } else if (tmplLine->type == LT_ECHO) {
3886        requote(tmplLine, config->cfi);
3887        static const char *prefix = "'Loading ";
3888        if (tmplLine->numElements > 1 &&
3889        strstr(tmplLine->elements[1].item, prefix) &&
3890        masterLine->next &&
3891        iskernel(masterLine->next->type)) {
3892     char *newTitle = malloc(strlen(prefix) +
3893     strlen(newKernelTitle) + 2);
3894    
3895     strcpy(newTitle, prefix);
3896     strcat(newTitle, newKernelTitle);
3897     strcat(newTitle, "'");
3898     newLine = addLine(new, config->cfi, LT_ECHO,
3899     tmplLine->indent, newTitle);
3900     free(newTitle);
3901        } else {
3902     /* pass through other lines from the template */
3903     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3904     config->cfi);
3905        }
3906        } else {
3907     /* pass through other lines from the template */
3908     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3909        }
3910   }   }
3911    
3912      } else {      } else {
3913   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3914      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3915     */
3916     switch (config->cfi->entryStart) {
3917        case LT_KERNEL:
3918        case LT_KERNEL_EFI:
3919     if (new->multiboot && config->cfi->mbHyperFirst) {
3920        /* fall through to LT_HYPER */
3921     } else {
3922        newLine = addLine(new, config->cfi,
3923              preferredLineType(LT_KERNEL, config->cfi),
3924          config->primaryIndent,
3925          newKernelPath + strlen(prefix));
3926        needs &= ~NEED_KERNEL;
3927        break;
3928     }
3929    
3930        case LT_HYPER:
3931     newLine = addLine(new, config->cfi, LT_HYPER,
3932      config->primaryIndent,
3933      newMBKernel + strlen(prefix));
3934     needs &= ~NEED_MB;
3935   break;   break;
         }  
3936    
3937   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3938      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3939       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3940       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3941      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3942       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3943      default:        config->primaryIndent, nkt);
3944                  /* zipl strikes again */   free(nkt);
3945                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3946                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3947                      chptr = newKernelTitle;   break;
3948                      type = LT_TITLE;      }
3949                      break;      case LT_TITLE:
3950                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3951                      abort();   char * templabel;
3952                  }   int x = 0, y = 0;
3953   }  
3954     templabel = strdup(newKernelTitle);
3955     while( templabel[x]){
3956     if( templabel[x] == ' ' ){
3957     y = x;
3958     while( templabel[y] ){
3959     templabel[y] = templabel[y+1];
3960     y++;
3961     }
3962     }
3963     x++;
3964     }
3965     newLine = addLine(new, config->cfi, LT_TITLE,
3966      config->primaryIndent, templabel);
3967     free(templabel);
3968     }else{
3969     newLine = addLine(new, config->cfi, LT_TITLE,
3970      config->primaryIndent, newKernelTitle);
3971     }
3972     needs &= ~NEED_TITLE;
3973     break;
3974    
3975   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3976   new->lines = newLine;   abort();
3977     }
3978      }      }
3979    
3980      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3981          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3982              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3983                                config->secondaryIndent,       */
3984                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3985          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3986              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3987                                config->secondaryIndent,    newKernelTitle);
3988                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3989          /* don't need to check for title as it's guaranteed to have been      }
3990           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3991           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3992          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3993              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3994                                config->secondaryIndent,   needs &= ~NEED_MB;
3995                                newKernelInitrd + strlen(prefix));      }
3996      } else {      if (needs & NEED_KERNEL) {
3997          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3998              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3999                                config->secondaryIndent,        config->cfi))
4000                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
4001          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
4002              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
4003                                config->secondaryIndent,    newKernelPath + strlen(prefix));
4004                                newKernelTitle);   needs &= ~NEED_KERNEL;
4005          if (needs & KERNEL_INITRD && newKernelInitrd)      }
4006              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
4007                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
4008                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
4009      newMBKernel + strlen(prefix));
4010     needs &= ~NEED_MB;
4011        }
4012        if (needs & NEED_INITRD) {
4013     char *initrdVal;
4014     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4015     newLine = addLine(new, config->cfi,
4016      (new->multiboot && getKeywordByType(LT_MBMODULE,
4017          config->cfi))
4018       ? LT_MBMODULE
4019       : preferredLineType(LT_INITRD, config->cfi),
4020      config->secondaryIndent,
4021      initrdVal);
4022     free(initrdVal);
4023     needs &= ~NEED_INITRD;
4024        }
4025        if (needs & NEED_END) {
4026     newLine = addLine(new, config->cfi, LT_ENTRY_END,
4027     config->secondaryIndent, NULL);
4028     needs &= ~NEED_END;
4029        }
4030    
4031        if (needs) {
4032     printf(_("grubby: needs=%d, aborting\n"), needs);
4033     abort();
4034      }      }
4035    
4036      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 4039  int addNewKernel(struct grubConfig * con
4039      return 0;      return 0;
4040  }  }
4041    
4042    static void traceback(int signum)
4043    {
4044        void *array[40];
4045        size_t size;
4046    
4047        signal(SIGSEGV, SIG_DFL);
4048        memset(array, '\0', sizeof (array));
4049        size = backtrace(array, 40);
4050    
4051        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4052                (unsigned long)size);
4053        backtrace_symbols_fd(array, size, STDERR_FILENO);
4054        exit(1);
4055    }
4056    
4057  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4058      poptContext optCon;      poptContext optCon;
4059      char * grubConfig = NULL;      const char * grubConfig = NULL;
4060      char * outputFile = NULL;      char * outputFile = NULL;
4061      int arg = 0;      int arg = 0;
4062      int flags = 0;      int flags = 0;
4063      int badImageOkay = 0;      int badImageOkay = 0;
4064        int configureGrub2 = 0;
4065      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4066      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4067        int configureExtLinux = 0;
4068      int bootloaderProbe = 0;      int bootloaderProbe = 0;
4069        int extraInitrdCount = 0;
4070      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
4071      char * newKernelPath = NULL;      char * newKernelPath = NULL;
4072      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 4082  int main(int argc, const char ** argv) {
4082      char * defaultKernel = NULL;      char * defaultKernel = NULL;
4083      char * removeArgs = NULL;      char * removeArgs = NULL;
4084      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4085        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4086        char * envPath = NULL;
4087      const char * chptr = NULL;      const char * chptr = NULL;
4088      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4089      struct grubConfig * config;      struct grubConfig * config;
4090      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4091      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4092      int displayDefault = 0;      int displayDefault = 0;
4093        int displayDefaultIndex = 0;
4094        int displayDefaultTitle = 0;
4095        int defaultIndex = -1;
4096      struct poptOption options[] = {      struct poptOption options[] = {
4097   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4098      _("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 4110  int main(int argc, const char ** argv) {
4110   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4111      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4112      _("bootfs") },      _("bootfs") },
4113  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4114   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4115      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4116  #endif  #endif
4117   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4118      _("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 4123  int main(int argc, const char ** argv) {
4123        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4124        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4125        "template"), NULL },        "template"), NULL },
4126     { "debug", 0, 0, &debug, 0,
4127        _("print debugging information for failures") },
4128   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4129      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4130     { "default-index", 0, 0, &displayDefaultIndex, 0,
4131        _("display the index of the default kernel") },
4132     { "default-title", 0, 0, &displayDefaultTitle, 0,
4133        _("display the title of the default kernel") },
4134   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4135      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4136     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4137        _("force grub2 stanzas to use efi") },
4138     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4139        _("path for environment data"),
4140        _("path") },
4141     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4142        _("configure extlinux bootloader (from syslinux)") },
4143   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4144      _("configure grub bootloader") },      _("configure grub bootloader") },
4145     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4146        _("configure grub2 bootloader") },
4147   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4148      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4149      _("kernel-path") },      _("kernel-path") },
4150   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4151      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4152     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4153        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4154   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4155      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4156   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4170  int main(int argc, const char ** argv) {
4170   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4171      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4172        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4173     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4174        _("make the given entry index the default entry"),
4175        _("entry-index") },
4176   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4177      _("configure silo bootloader") },      _("configure silo bootloader") },
4178   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4190  int main(int argc, const char ** argv) {
4190   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4191      };      };
4192    
4193        useextlinuxmenu=0;
4194    
4195        signal(SIGSEGV, traceback);
4196    
4197        int i = 0;
4198        for (int j = 1; j < argc; j++)
4199     i += strlen(argv[j]) + 1;
4200        saved_command_line = malloc(i);
4201        if (!saved_command_line) {
4202     fprintf(stderr, "grubby: %m\n");
4203     exit(1);
4204        }
4205        saved_command_line[0] = '\0';
4206        for (int j = 1; j < argc; j++) {
4207     strcat(saved_command_line, argv[j]);
4208     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4209        }
4210    
4211      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4212      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4213    
# Line 2391  int main(int argc, const char ** argv) { Line 4217  int main(int argc, const char ** argv) {
4217      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4218      exit(0);      exit(0);
4219      break;      break;
4220      case 'i':
4221        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4222         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4223        } else {
4224     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4225     return 1;
4226        }
4227        break;
4228   }   }
4229      }      }
4230    
# Line 2406  int main(int argc, const char ** argv) { Line 4240  int main(int argc, const char ** argv) {
4240   return 1;   return 1;
4241      }      }
4242    
4243      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4244   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4245     configureExtLinux ) > 1) {
4246   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4247   return 1;   return 1;
4248      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4249   fprintf(stderr,   fprintf(stderr,
4250      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4251   return 1;   return 1;
4252        } else if (configureGrub2) {
4253     cfi = &grub2ConfigType;
4254     if (envPath)
4255        cfi->envFile = envPath;
4256      } else if (configureLilo) {      } else if (configureLilo) {
4257   cfi = &liloConfigType;   cfi = &liloConfigType;
4258      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4265  int main(int argc, const char ** argv) {
4265          cfi = &siloConfigType;          cfi = &siloConfigType;
4266      } else if (configureZipl) {      } else if (configureZipl) {
4267          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4268        } else if (configureExtLinux) {
4269     cfi = &extlinuxConfigType;
4270     useextlinuxmenu=1;
4271      }      }
4272    
4273      if (!cfi) {      if (!cfi) {
4274            if (grub2FindConfig(&grub2ConfigType))
4275        cfi = &grub2ConfigType;
4276     else
4277        #ifdef __ia64__        #ifdef __ia64__
4278   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4279        #elif __powerpc__        #elif __powerpc__
4280   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4281        #elif __sparc__        #elif __sparc__
4282          cfi = &siloConfigType;              cfi = &siloConfigType;
4283        #elif __s390__        #elif __s390__
4284          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4285        #elif __s390x__        #elif __s390x__
4286          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4287        #else        #else
4288   cfi = &grubConfigType;      cfi = &grubConfigType;
4289        #endif        #endif
4290      }      }
4291    
4292      if (!grubConfig)      if (!grubConfig) {
4293   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4294        grubConfig = cfi->findConfig(cfi);
4295     if (!grubConfig)
4296        grubConfig = cfi->defaultConfig;
4297        }
4298    
4299      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4300    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4301    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4302        (defaultIndex >= 0))) {
4303   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4304    "specified option"));    "specified option"));
4305   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4315  int main(int argc, const char ** argv) {
4315      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4316   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4317   return 1;   return 1;
4318      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4319    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4320    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4321   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4322   return 1;   return 1;
4323      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4341  int main(int argc, const char ** argv) {
4341   makeDefault = 1;   makeDefault = 1;
4342   defaultKernel = NULL;   defaultKernel = NULL;
4343      }      }
4344        else if (defaultKernel && (defaultIndex >= 0)) {
4345     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4346      "may not be used together\n"));
4347     return 1;
4348        }
4349    
4350      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4351   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4352   "is used\n"));   "is used\n"));
4353   return 1;   return 1;
4354      }      }
4355    
4356      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4357   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4358          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4359     && (defaultIndex == -1)) {
4360   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4361   return 1;   return 1;
4362      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4376  int main(int argc, const char ** argv) {
4376   bootPrefix = "";   bootPrefix = "";
4377      }      }
4378    
4379        if (!cfi->mbAllowExtraInitRds &&
4380     extraInitrdCount > 0) {
4381     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4382     return 1;
4383        }
4384    
4385      if (bootloaderProbe) {      if (bootloaderProbe) {
4386   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4387   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4388    
4389     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4390     if (grub2config) {
4391        gconfig = readConfig(grub2config, &grub2ConfigType);
4392        if (!gconfig)
4393     gr2c = 1;
4394        else
4395     gr2c = checkForGrub2(gconfig);
4396     }
4397    
4398   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4399      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4400        gconfig = readConfig(grubconfig, &grubConfigType);
4401      if (!gconfig)      if (!gconfig)
4402   grc = 1;   grc = 1;
4403      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4412  int main(int argc, const char ** argv) {
4412   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4413   }   }
4414    
4415   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4416        econfig = readConfig(eliloConfigType.defaultConfig,
4417     &eliloConfigType);
4418        if (!econfig)
4419     erc = 1;
4420        else
4421     erc = checkForElilo(econfig);
4422     }
4423    
4424     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4425        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4426        if (!lconfig)
4427     extrc = 1;
4428        else
4429     extrc = checkForExtLinux(lconfig);
4430     }
4431    
4432    
4433     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4434        yconfig = readConfig(yabootConfigType.defaultConfig,
4435     &yabootConfigType);
4436        if (!yconfig)
4437     yrc = 1;
4438        else
4439     yrc = checkForYaboot(yconfig);
4440     }
4441    
4442     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4443     erc == 1)
4444        return 1;
4445    
4446   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4447     if (gr2c == 2) printf("grub2\n");
4448   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4449     if (extrc == 2) printf("extlinux\n");
4450     if (yrc == 2) printf("yaboot\n");
4451     if (erc == 2) printf("elilo\n");
4452    
4453   return 0;   return 0;
4454      }      }
4455    
4456        if (grubConfig == NULL) {
4457     printf("Could not find bootloader configuration file.\n");
4458     exit(1);
4459        }
4460    
4461      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4462      if (!config) return 1;      if (!config) return 1;
4463    
# Line 2557  int main(int argc, const char ** argv) { Line 4467  int main(int argc, const char ** argv) {
4467          char * rootspec;          char * rootspec;
4468    
4469   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4470     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4471     cfi->defaultIsSaved)
4472        config->defaultImage = 0;
4473   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4474   if (!entry) return 0;   if (!entry) return 0;
4475   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4476    
4477   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4478   if (!line) return 0;   if (!line) return 0;
4479    
4480          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4482  int main(int argc, const char ** argv) {
4482                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4483    
4484   return 0;   return 0;
4485    
4486        } else if (displayDefaultTitle) {
4487     struct singleLine * line;
4488     struct singleEntry * entry;
4489    
4490     if (config->defaultImage == -1) return 0;
4491     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4492     cfi->defaultIsSaved)
4493        config->defaultImage = 0;
4494     entry = findEntryByIndex(config, config->defaultImage);
4495     if (!entry) return 0;
4496    
4497     if (!configureGrub2) {
4498      line = getLineByType(LT_TITLE, entry->lines);
4499      if (!line) return 0;
4500      printf("%s\n", line->elements[1].item);
4501    
4502     } else {
4503      char * title;
4504    
4505      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4506      line = getLineByType(LT_MENUENTRY, entry->lines);
4507      if (!line) return 0;
4508      title = grub2ExtractTitle(line);
4509      if (title)
4510        printf("%s\n", title);
4511     }
4512     return 0;
4513    
4514        } else if (displayDefaultIndex) {
4515            if (config->defaultImage == -1) return 0;
4516     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4517     cfi->defaultIsSaved)
4518        config->defaultImage = 0;
4519            printf("%i\n", config->defaultImage);
4520            return 0;
4521    
4522      } else if (kernelInfo)      } else if (kernelInfo)
4523   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4524    
# Line 2581  int main(int argc, const char ** argv) { Line 4530  int main(int argc, const char ** argv) {
4530      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4531      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4532      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4533      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4534      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4535      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4536                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4537        if (updateKernelPath && newKernelInitrd) {
4538        if (newMBKernel) {
4539        if (addMBInitrd(config, newMBKernel, updateKernelPath,
4540     bootPrefix, newKernelInitrd))
4541        return 1;
4542        } else {
4543        if (updateInitrd(config, updateKernelPath, bootPrefix,
4544     newKernelInitrd))
4545     return 1;
4546        }
4547        }
4548      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4549                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4550                         (const char **)extraInitrds, extraInitrdCount,
4551                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4552            
4553    
# Line 2597  int main(int argc, const char ** argv) { Line 4558  int main(int argc, const char ** argv) {
4558      }      }
4559    
4560      if (!outputFile)      if (!outputFile)
4561   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4562    
4563      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4564  }  }

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