Magellan Linux

Diff of /trunk/grubby/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 2262 by niro, Mon Oct 21 14:06:22 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 1553  void removeLine(struct singleEntry * ent Line 2872  void removeLine(struct singleEntry * ent
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) {
3017      char * first, * second;      char * first, * second;
3018      char * chptr;      char * chptr;
# 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 updateInitrd(struct grubConfig * cfg, const char * image,
3262                     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, image, prefix, &index)); index++) {
3270            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3271            if (!kernelLine) continue;
3272    
3273            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3274            if (line)
3275                removeLine(entry, line);
3276            if (prefix) {
3277                int prefixLen = strlen(prefix);
3278                if (!strncmp(initrd, prefix, prefixLen))
3279                    initrd += prefixLen;
3280            }
3281     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3282     if (endLine)
3283        removeLine(entry, endLine);
3284            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3285     kernelLine->indent, initrd);
3286            if (!line)
3287        return 1;
3288     if (endLine) {
3289        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3290                if (!line)
3291     return 1;
3292     }
3293    
3294            break;
3295        }
3296    
3297        return 0;
3298    }
3299    
3300  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3301      int fd;      int fd;
3302      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3320  int checkDeviceBootloader(const char * d
3320      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3321   return 0;   return 0;
3322    
3323      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3324   offset = boot[2] + 2;   offset = boot[2] + 2;
3325      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3326   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3327      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3328   offset = boot[1] + 2;        offset = boot[1] + 2;
3329            /*
3330     * it looks like grub, when copying stage1 into the mbr, patches stage1
3331     * right after the JMP location, replacing other instructions such as
3332     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3333     * different bytes.
3334     */
3335          if ((bootSect[offset + 1] == NOOP_OPCODE)
3336      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3337     offset = offset + 3;
3338          }
3339      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3340   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3341      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3477  int checkForLilo(struct grubConfig * con
3477      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3478  }  }
3479    
3480    int checkForGrub2(struct grubConfig * config) {
3481        if (!access("/etc/grub.d/", R_OK))
3482     return 2;
3483    
3484        return 1;
3485    }
3486    
3487  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3488      int fd;      int fd;
3489      unsigned char bootSect[512];      unsigned char bootSect[512];
3490      char * boot;      char * boot;
3491        int onSuse = isSuseSystem();
3492    
3493      if (parseSysconfigGrub(NULL, &boot))  
3494   return 0;      if (onSuse) {
3495     if (parseSuseGrubConf(NULL, &boot))
3496        return 0;
3497        } else {
3498     if (parseSysconfigGrub(NULL, &boot))
3499        return 0;
3500        }
3501    
3502      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3503      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3511  int checkForGrub(struct grubConfig * con
3511      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3512   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3513   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3514     close(fd);
3515   return 1;   return 1;
3516      }      }
3517      close(fd);      close(fd);
3518    
3519        /* The more elaborate checks do not work on SuSE. The checks done
3520         * seem to be reasonble (at least for now), so just return success
3521         */
3522        if (onSuse)
3523     return 2;
3524    
3525      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3526  }  }
3527    
3528    int checkForExtLinux(struct grubConfig * config) {
3529        int fd;
3530        unsigned char bootSect[512];
3531        char * boot;
3532        char executable[] = "/boot/extlinux/extlinux";
3533    
3534        printf("entered: checkForExtLinux()\n");
3535    
3536        if (parseSysconfigGrub(NULL, &boot))
3537     return 0;
3538    
3539        /* assume grub is not installed -- not an error condition */
3540        if (!boot)
3541     return 0;
3542    
3543        fd = open(executable, O_RDONLY);
3544        if (fd < 0)
3545     /* this doesn't exist if grub hasn't been installed */
3546     return 0;
3547    
3548        if (read(fd, bootSect, 512) != 512) {
3549     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3550     executable, strerror(errno));
3551     return 1;
3552        }
3553        close(fd);
3554    
3555        return checkDeviceBootloader(boot, bootSect);
3556    }
3557    
3558    int checkForYaboot(struct grubConfig * config) {
3559        /*
3560         * This is a simplistic check that we consider good enough for own puporses
3561         *
3562         * If we were to properly check if yaboot is *installed* we'd need to:
3563         * 1) get the system boot device (LT_BOOT)
3564         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3565         *    the content on the boot device
3566         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3567         * 4) check again if binary and boot device contents match
3568         */
3569        if (!access("/etc/yaboot.conf", R_OK))
3570     return 2;
3571    
3572        return 1;
3573    }
3574    
3575    int checkForElilo(struct grubConfig * config) {
3576        if (!access("/etc/elilo.conf", R_OK))
3577     return 2;
3578    
3579        return 1;
3580    }
3581    
3582  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3583      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3584    
# Line 1994  static char * getRootSpecifier(char * st Line 3590  static char * getRootSpecifier(char * st
3590      return rootspec;      return rootspec;
3591  }  }
3592    
3593    static char * getInitrdVal(struct grubConfig * config,
3594       const char * prefix, struct singleLine *tmplLine,
3595       const char * newKernelInitrd,
3596       const char ** extraInitrds, int extraInitrdCount)
3597    {
3598        char *initrdVal, *end;
3599        int i;
3600        size_t totalSize;
3601        size_t prefixLen;
3602        char separatorChar;
3603    
3604        prefixLen = strlen(prefix);
3605        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3606    
3607        for (i = 0; i < extraInitrdCount; i++) {
3608     totalSize += sizeof(separatorChar);
3609     totalSize += strlen(extraInitrds[i]) - prefixLen;
3610        }
3611    
3612        initrdVal = end = malloc(totalSize);
3613    
3614        end = stpcpy (end, newKernelInitrd + prefixLen);
3615    
3616        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3617        for (i = 0; i < extraInitrdCount; i++) {
3618     const char *extraInitrd;
3619     int j;
3620    
3621     extraInitrd = extraInitrds[i] + prefixLen;
3622     /* Don't add entries that are already there */
3623     if (tmplLine != NULL) {
3624        for (j = 2; j < tmplLine->numElements; j++)
3625     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3626        break;
3627    
3628        if (j != tmplLine->numElements)
3629     continue;
3630     }
3631    
3632     *end++ = separatorChar;
3633     end = stpcpy(end, extraInitrd);
3634        }
3635    
3636        return initrdVal;
3637    }
3638    
3639  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3640           const char * prefix,           const char * prefix,
3641   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3642   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3643                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3644                     const char * newMBKernel, const char * newMBKernelArgs) {
3645      struct singleEntry * new;      struct singleEntry * new;
3646      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3647      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3648      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3649    
3650      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3651    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3675  int addNewKernel(struct grubConfig * con
3675      config->entries = new;      config->entries = new;
3676    
3677      /* copy/update from the template */      /* copy/update from the template */
3678      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3679        if (newKernelInitrd)
3680     needs |= NEED_INITRD;
3681      if (newMBKernel) {      if (newMBKernel) {
3682          needs |= KERNEL_MB;          needs |= NEED_MB;
3683          new->multiboot = 1;          new->multiboot = 1;
3684      }      }
3685    
3686      if (template) {      if (template) {
3687   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3688      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3689      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3690   indent = tmplLine->indent;   {
3691        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3692    
3693      /* skip comments */      /* skip comments */
3694      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3695      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3696      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3697    
3698      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3699      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3700        /* it's not a multiboot template and this is the kernel
3701              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3702                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3703                  struct singleLine *l;       */
3704                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3705     /* insert the hypervisor first */
3706                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3707                                    config->secondaryIndent,    tmplLine->indent,
3708                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3709                     /* set up for adding the kernel line */
3710                  tmplLine = lastLine;   free(tmplLine->indent);
3711                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3712                      new->lines = l;   needs &= ~NEED_MB;
3713                  } else {      }
3714                      newLine->next = l;      if (needs & NEED_KERNEL) {
3715                      newLine = l;   /* use addLineTmpl to preserve line elements,
3716                  }   * otherwise we could just call addLine.  Unfortunately
3717                  continue;   * this means making some changes to the template
3718              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3719                         template->multiboot && !new->multiboot) {   * change below.
3720                  continue; /* don't need multiboot kernel here */   */
3721              }   struct keywordTypes * mbm_kw =
3722        getKeywordByType(LT_MBMODULE, config->cfi);
3723      if (!new->lines) {   if (mbm_kw) {
3724   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3725   new->lines = newLine;      free(tmplLine->elements[0].item);
3726      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3727   newLine->next = malloc(sizeof(*newLine));   }
3728   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3729      }        newKernelPath + strlen(prefix), config->cfi);
3730     needs &= ~NEED_KERNEL;
3731        }
3732        if (needs & NEED_MB) { /* !mbHyperFirst */
3733     newLine = addLine(new, config->cfi, LT_HYPER,
3734      config->secondaryIndent,
3735      newMBKernel + strlen(prefix));
3736     needs &= ~NEED_MB;
3737        }
3738     } else if (needs & NEED_KERNEL) {
3739        newLine = addLineTmpl(new, tmplLine, newLine,
3740      newKernelPath + strlen(prefix), config->cfi);
3741        needs &= ~NEED_KERNEL;
3742     }
3743    
3744        } else if (tmplLine->type == LT_HYPER &&
3745           tmplLine->numElements >= 2) {
3746     if (needs & NEED_MB) {
3747        newLine = addLineTmpl(new, tmplLine, newLine,
3748      newMBKernel + strlen(prefix), config->cfi);
3749        needs &= ~NEED_MB;
3750     }
3751    
3752      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3753      newLine->next = NULL;         tmplLine->numElements >= 2) {
3754      newLine->type = tmplLine->type;   if (new->multiboot) {
3755      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3756      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3757      newLine->numElements);        newKernelPath +
3758      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3759   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3760   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3761   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3762      }   char *initrdVal;
3763     initrdVal = getInitrdVal(config, prefix, tmplLine,
3764              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3765      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3766                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3767                  if (!template->multiboot) {        initrdVal, config->cfi);
3768                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3769                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3770                  } else {      }
3771                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3772                      repl = newMBKernel;      /* template is multi but new is not,
3773                  }       * insert the kernel in the first module slot
3774                  if (new->multiboot && !template->multiboot) {       */
3775                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3776                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3777                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3778                  }   strdup(getKeywordByType(tmplLine->type,
3779   free(newLine->elements[1].item);   config->cfi)->key);
3780                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3781                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3782                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3783                                                             rootspec,      needs &= ~NEED_KERNEL;
3784                                                             repl +   } else if (needs & NEED_INITRD) {
3785                                                             strlen(prefix));      char *initrdVal;
3786                  } else {      /* template is multi but new is not,
3787                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3788                                                         strlen(prefix));       */
3789                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3790              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3791                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3792                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3793                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3794                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3795                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3796                      newLine->type = LT_KERNEL;      free(initrdVal);
3797                  }      needs &= ~NEED_INITRD;
3798   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;  
3799    
3800   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3801      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3802      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3803        config->cfi->mbInitRdIsModule) {
3804        /* make sure we don't insert the module initrd
3805         * before the module kernel... if we don't do it here,
3806         * it will be inserted following the template.
3807         */
3808        if (!needs & NEED_KERNEL) {
3809     char *initrdVal;
3810    
3811     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3812     newLine = addLine(new, config->cfi, LT_MBMODULE,
3813      config->secondaryIndent,
3814      initrdVal);
3815     free(initrdVal);
3816     needs &= ~NEED_INITRD;
3817        }
3818     } else if (needs & NEED_INITRD) {
3819        char *initrdVal;
3820        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3821        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3822        free(initrdVal);
3823        needs &= ~NEED_INITRD;
3824   }   }
3825    
3826   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3827   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3828   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3829     char *nkt = malloc(strlen(newKernelTitle)+3);
3830     strcpy(nkt, "'");
3831     strcat(nkt, newKernelTitle);
3832     strcat(nkt, "'");
3833     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3834     free(nkt);
3835     needs &= ~NEED_TITLE;
3836      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3837                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3838                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3839                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3840                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3841                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3842                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3843                                             newLine->numElements);     config->cfi->titleBracketed) {
3844        /* addLineTmpl doesn't handle titleBracketed */
3845                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3846                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3847                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3848                  newLine->numElements = 1;   }
3849              }      } else if (tmplLine->type == LT_ECHO) {
3850        requote(tmplLine, config->cfi);
3851        static const char *prefix = "'Loading ";
3852        if (tmplLine->numElements > 1 &&
3853        strstr(tmplLine->elements[1].item, prefix) &&
3854        masterLine->next &&
3855        iskernel(masterLine->next->type)) {
3856     char *newTitle = malloc(strlen(prefix) +
3857     strlen(newKernelTitle) + 2);
3858    
3859     strcpy(newTitle, prefix);
3860     strcat(newTitle, newKernelTitle);
3861     strcat(newTitle, "'");
3862     newLine = addLine(new, config->cfi, LT_ECHO,
3863     tmplLine->indent, newTitle);
3864     free(newTitle);
3865        } else {
3866     /* pass through other lines from the template */
3867     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3868     config->cfi);
3869        }
3870        } else {
3871     /* pass through other lines from the template */
3872     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3873        }
3874   }   }
3875    
3876      } else {      } else {
3877   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3878      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3879     */
3880     switch (config->cfi->entryStart) {
3881        case LT_KERNEL:
3882        case LT_KERNEL_EFI:
3883     if (new->multiboot && config->cfi->mbHyperFirst) {
3884        /* fall through to LT_HYPER */
3885     } else {
3886        newLine = addLine(new, config->cfi,
3887              preferredLineType(LT_KERNEL, config->cfi),
3888          config->primaryIndent,
3889          newKernelPath + strlen(prefix));
3890        needs &= ~NEED_KERNEL;
3891        break;
3892     }
3893    
3894        case LT_HYPER:
3895     newLine = addLine(new, config->cfi, LT_HYPER,
3896      config->primaryIndent,
3897      newMBKernel + strlen(prefix));
3898     needs &= ~NEED_MB;
3899   break;   break;
         }  
3900    
3901   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3902      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3903       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3904       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3905      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3906       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3907      default:        config->primaryIndent, nkt);
3908                  /* zipl strikes again */   free(nkt);
3909                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3910                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3911                      chptr = newKernelTitle;   break;
3912                      type = LT_TITLE;      }
3913                      break;      case LT_TITLE:
3914                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3915                      abort();   char * templabel;
3916                  }   int x = 0, y = 0;
3917   }  
3918     templabel = strdup(newKernelTitle);
3919     while( templabel[x]){
3920     if( templabel[x] == ' ' ){
3921     y = x;
3922     while( templabel[y] ){
3923     templabel[y] = templabel[y+1];
3924     y++;
3925     }
3926     }
3927     x++;
3928     }
3929     newLine = addLine(new, config->cfi, LT_TITLE,
3930      config->primaryIndent, templabel);
3931     free(templabel);
3932     }else{
3933     newLine = addLine(new, config->cfi, LT_TITLE,
3934      config->primaryIndent, newKernelTitle);
3935     }
3936     needs &= ~NEED_TITLE;
3937     break;
3938    
3939   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3940   new->lines = newLine;   abort();
3941     }
3942      }      }
3943    
3944      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3945          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3946              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3947                                config->secondaryIndent,       */
3948                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3949          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3950              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3951                                config->secondaryIndent,    newKernelTitle);
3952                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3953          /* don't need to check for title as it's guaranteed to have been      }
3954           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3955           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3956          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3957              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3958                                config->secondaryIndent,   needs &= ~NEED_MB;
3959                                newKernelInitrd + strlen(prefix));      }
3960      } else {      if (needs & NEED_KERNEL) {
3961          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3962              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3963                                config->secondaryIndent,        config->cfi))
3964                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3965          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3966              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3967                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3968                                newKernelTitle);   needs &= ~NEED_KERNEL;
3969          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3970              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3971                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3972                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3973      newMBKernel + strlen(prefix));
3974     needs &= ~NEED_MB;
3975        }
3976        if (needs & NEED_INITRD) {
3977     char *initrdVal;
3978     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3979     newLine = addLine(new, config->cfi,
3980      (new->multiboot && getKeywordByType(LT_MBMODULE,
3981          config->cfi))
3982       ? LT_MBMODULE
3983       : preferredLineType(LT_INITRD, config->cfi),
3984      config->secondaryIndent,
3985      initrdVal);
3986     free(initrdVal);
3987     needs &= ~NEED_INITRD;
3988        }
3989        if (needs & NEED_END) {
3990     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3991     config->secondaryIndent, NULL);
3992     needs &= ~NEED_END;
3993        }
3994    
3995        if (needs) {
3996     printf(_("grubby: needs=%d, aborting\n"), needs);
3997     abort();
3998      }      }
3999    
4000      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 4003  int addNewKernel(struct grubConfig * con
4003      return 0;      return 0;
4004  }  }
4005    
4006    static void traceback(int signum)
4007    {
4008        void *array[40];
4009        size_t size;
4010    
4011        signal(SIGSEGV, SIG_DFL);
4012        memset(array, '\0', sizeof (array));
4013        size = backtrace(array, 40);
4014    
4015        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4016                (unsigned long)size);
4017        backtrace_symbols_fd(array, size, STDERR_FILENO);
4018        exit(1);
4019    }
4020    
4021  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4022      poptContext optCon;      poptContext optCon;
4023      char * grubConfig = NULL;      const char * grubConfig = NULL;
4024      char * outputFile = NULL;      char * outputFile = NULL;
4025      int arg = 0;      int arg = 0;
4026      int flags = 0;      int flags = 0;
4027      int badImageOkay = 0;      int badImageOkay = 0;
4028        int configureGrub2 = 0;
4029      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4030      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4031        int configureExtLinux = 0;
4032      int bootloaderProbe = 0;      int bootloaderProbe = 0;
4033        int extraInitrdCount = 0;
4034      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
4035      char * newKernelPath = NULL;      char * newKernelPath = NULL;
4036      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 4046  int main(int argc, const char ** argv) {
4046      char * defaultKernel = NULL;      char * defaultKernel = NULL;
4047      char * removeArgs = NULL;      char * removeArgs = NULL;
4048      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4049        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4050        char * envPath = NULL;
4051      const char * chptr = NULL;      const char * chptr = NULL;
4052      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4053      struct grubConfig * config;      struct grubConfig * config;
4054      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4055      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4056      int displayDefault = 0;      int displayDefault = 0;
4057        int displayDefaultIndex = 0;
4058        int displayDefaultTitle = 0;
4059        int defaultIndex = -1;
4060      struct poptOption options[] = {      struct poptOption options[] = {
4061   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4062      _("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 4074  int main(int argc, const char ** argv) {
4074   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4075      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4076      _("bootfs") },      _("bootfs") },
4077  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4078   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4079      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4080  #endif  #endif
4081   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4082      _("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 4087  int main(int argc, const char ** argv) {
4087        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4088        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4089        "template"), NULL },        "template"), NULL },
4090     { "debug", 0, 0, &debug, 0,
4091        _("print debugging information for failures") },
4092   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4093      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4094     { "default-index", 0, 0, &displayDefaultIndex, 0,
4095        _("display the index of the default kernel") },
4096     { "default-title", 0, 0, &displayDefaultTitle, 0,
4097        _("display the title of the default kernel") },
4098   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4099      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4100     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4101        _("force grub2 stanzas to use efi") },
4102     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4103        _("path for environment data"),
4104        _("path") },
4105     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4106        _("configure extlinux bootloader (from syslinux)") },
4107   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4108      _("configure grub bootloader") },      _("configure grub bootloader") },
4109     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4110        _("configure grub2 bootloader") },
4111   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4112      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4113      _("kernel-path") },      _("kernel-path") },
4114   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4115      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4116     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4117        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4118   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4119      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4120   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 4134  int main(int argc, const char ** argv) {
4134   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4135      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4136        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4137     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4138        _("make the given entry index the default entry"),
4139        _("entry-index") },
4140   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4141      _("configure silo bootloader") },      _("configure silo bootloader") },
4142   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 4154  int main(int argc, const char ** argv) {
4154   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
4155      };      };
4156    
4157        useextlinuxmenu=0;
4158    
4159        signal(SIGSEGV, traceback);
4160    
4161        int i = 0;
4162        for (int j = 1; j < argc; j++)
4163     i += strlen(argv[j]) + 1;
4164        saved_command_line = malloc(i);
4165        if (!saved_command_line) {
4166     fprintf(stderr, "grubby: %m\n");
4167     exit(1);
4168        }
4169        saved_command_line[0] = '\0';
4170        for (int j = 1; j < argc; j++) {
4171     strcat(saved_command_line, argv[j]);
4172     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4173        }
4174    
4175      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4176      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4177    
# Line 2391  int main(int argc, const char ** argv) { Line 4181  int main(int argc, const char ** argv) {
4181      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
4182      exit(0);      exit(0);
4183      break;      break;
4184      case 'i':
4185        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
4186         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
4187        } else {
4188     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
4189     return 1;
4190        }
4191        break;
4192   }   }
4193      }      }
4194    
# Line 2406  int main(int argc, const char ** argv) { Line 4204  int main(int argc, const char ** argv) {
4204   return 1;   return 1;
4205      }      }
4206    
4207      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4208   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
4209     configureExtLinux ) > 1) {
4210   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
4211   return 1;   return 1;
4212      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
4213   fprintf(stderr,   fprintf(stderr,
4214      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4215   return 1;   return 1;
4216        } else if (configureGrub2) {
4217     cfi = &grub2ConfigType;
4218     if (envPath)
4219        cfi->envFile = envPath;
4220      } else if (configureLilo) {      } else if (configureLilo) {
4221   cfi = &liloConfigType;   cfi = &liloConfigType;
4222      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4229  int main(int argc, const char ** argv) {
4229          cfi = &siloConfigType;          cfi = &siloConfigType;
4230      } else if (configureZipl) {      } else if (configureZipl) {
4231          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4232        } else if (configureExtLinux) {
4233     cfi = &extlinuxConfigType;
4234     useextlinuxmenu=1;
4235      }      }
4236    
4237      if (!cfi) {      if (!cfi) {
4238            if (grub2FindConfig(&grub2ConfigType))
4239        cfi = &grub2ConfigType;
4240     else
4241        #ifdef __ia64__        #ifdef __ia64__
4242   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4243        #elif __powerpc__        #elif __powerpc__
4244   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4245        #elif __sparc__        #elif __sparc__
4246          cfi = &siloConfigType;              cfi = &siloConfigType;
4247        #elif __s390__        #elif __s390__
4248          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4249        #elif __s390x__        #elif __s390x__
4250          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4251        #else        #else
4252   cfi = &grubConfigType;      cfi = &grubConfigType;
4253        #endif        #endif
4254      }      }
4255    
4256      if (!grubConfig)      if (!grubConfig) {
4257   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4258        grubConfig = cfi->findConfig(cfi);
4259     if (!grubConfig)
4260        grubConfig = cfi->defaultConfig;
4261        }
4262    
4263      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4264    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4265    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4266        (defaultIndex >= 0))) {
4267   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4268    "specified option"));    "specified option"));
4269   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4279  int main(int argc, const char ** argv) {
4279      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4280   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4281   return 1;   return 1;
4282      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4283    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4284    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4285   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4286   return 1;   return 1;
4287      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4305  int main(int argc, const char ** argv) {
4305   makeDefault = 1;   makeDefault = 1;
4306   defaultKernel = NULL;   defaultKernel = NULL;
4307      }      }
4308        else if (defaultKernel && (defaultIndex >= 0)) {
4309     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4310      "may not be used together\n"));
4311     return 1;
4312        }
4313    
4314      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4315   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4316   "is used\n"));   "is used\n"));
4317   return 1;   return 1;
4318      }      }
4319    
4320      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4321   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4322          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4323     && (defaultIndex == -1)) {
4324   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4325   return 1;   return 1;
4326      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4340  int main(int argc, const char ** argv) {
4340   bootPrefix = "";   bootPrefix = "";
4341      }      }
4342    
4343        if (!cfi->mbAllowExtraInitRds &&
4344     extraInitrdCount > 0) {
4345     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4346     return 1;
4347        }
4348    
4349      if (bootloaderProbe) {      if (bootloaderProbe) {
4350   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4351   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4352    
4353     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4354     if (grub2config) {
4355        gconfig = readConfig(grub2config, &grub2ConfigType);
4356        if (!gconfig)
4357     gr2c = 1;
4358        else
4359     gr2c = checkForGrub2(gconfig);
4360     }
4361    
4362   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4363      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4364        gconfig = readConfig(grubconfig, &grubConfigType);
4365      if (!gconfig)      if (!gconfig)
4366   grc = 1;   grc = 1;
4367      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4376  int main(int argc, const char ** argv) {
4376   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4377   }   }
4378    
4379   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4380        econfig = readConfig(eliloConfigType.defaultConfig,
4381     &eliloConfigType);
4382        if (!econfig)
4383     erc = 1;
4384        else
4385     erc = checkForElilo(econfig);
4386     }
4387    
4388     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4389        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4390        if (!lconfig)
4391     extrc = 1;
4392        else
4393     extrc = checkForExtLinux(lconfig);
4394     }
4395    
4396    
4397     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4398        yconfig = readConfig(yabootConfigType.defaultConfig,
4399     &yabootConfigType);
4400        if (!yconfig)
4401     yrc = 1;
4402        else
4403     yrc = checkForYaboot(yconfig);
4404     }
4405    
4406     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4407     erc == 1)
4408        return 1;
4409    
4410   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4411     if (gr2c == 2) printf("grub2\n");
4412   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4413     if (extrc == 2) printf("extlinux\n");
4414     if (yrc == 2) printf("yaboot\n");
4415     if (erc == 2) printf("elilo\n");
4416    
4417   return 0;   return 0;
4418      }      }
4419    
4420        if (grubConfig == NULL) {
4421     printf("Could not find bootloader configuration file.\n");
4422     exit(1);
4423        }
4424    
4425      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4426      if (!config) return 1;      if (!config) return 1;
4427    
# Line 2557  int main(int argc, const char ** argv) { Line 4431  int main(int argc, const char ** argv) {
4431          char * rootspec;          char * rootspec;
4432    
4433   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4434     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4435     cfi->defaultIsSaved)
4436        config->defaultImage = 0;
4437   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4438   if (!entry) return 0;   if (!entry) return 0;
4439   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4440    
4441   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4442   if (!line) return 0;   if (!line) return 0;
4443    
4444          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4446  int main(int argc, const char ** argv) {
4446                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4447    
4448   return 0;   return 0;
4449    
4450        } else if (displayDefaultTitle) {
4451     struct singleLine * line;
4452     struct singleEntry * entry;
4453    
4454     if (config->defaultImage == -1) return 0;
4455     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4456     cfi->defaultIsSaved)
4457        config->defaultImage = 0;
4458     entry = findEntryByIndex(config, config->defaultImage);
4459     if (!entry) return 0;
4460    
4461     if (!configureGrub2) {
4462      line = getLineByType(LT_TITLE, entry->lines);
4463      if (!line) return 0;
4464      printf("%s\n", line->elements[1].item);
4465    
4466     } else {
4467      char * title;
4468    
4469      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4470      line = getLineByType(LT_MENUENTRY, entry->lines);
4471      if (!line) return 0;
4472      title = grub2ExtractTitle(line);
4473      if (title)
4474        printf("%s\n", title);
4475     }
4476     return 0;
4477    
4478        } else if (displayDefaultIndex) {
4479            if (config->defaultImage == -1) return 0;
4480     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4481     cfi->defaultIsSaved)
4482        config->defaultImage = 0;
4483            printf("%i\n", config->defaultImage);
4484            return 0;
4485    
4486      } else if (kernelInfo)      } else if (kernelInfo)
4487   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4488    
# Line 2581  int main(int argc, const char ** argv) { Line 4494  int main(int argc, const char ** argv) {
4494      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4495      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4496      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4497      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4498      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4499      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4500                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4501        if (updateKernelPath && newKernelInitrd) {
4502                if (updateInitrd(config, updateKernelPath, bootPrefix,
4503                                 newKernelInitrd)) return 1;
4504        }
4505      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4506                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4507                         (const char **)extraInitrds, extraInitrdCount,
4508                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4509            
4510    
# Line 2597  int main(int argc, const char ** argv) { Line 4515  int main(int argc, const char ** argv) {
4515      }      }
4516    
4517      if (!outputFile)      if (!outputFile)
4518   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4519    
4520      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4521  }  }

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