Magellan Linux

Diff of /tags/grubby-8_21/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 1746 by niro, Sat Feb 18 01:06:20 2012 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    #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43  #include "mount_by_label.h"  #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49    int debug = 0; /* Currently just for template debugging */
50    
51  #define _(A) (A)  #define _(A) (A)
52    
53    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
54  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
55    
56    #define NOOP_OPCODE 0x90
57    #define JMP_SHORT_OPCODE 0xeb
58    
59  /* comments get lumped in with indention */  /* comments get lumped in with indention */
60  struct lineElement {  struct lineElement {
61      char * item;      char * item;
62      char * indent;      char * indent;
63  };  };
64    
65  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
66         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
67         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
68        LT_KERNEL       = 1 << 2,
69        LT_INITRD       = 1 << 3,
70        LT_HYPER        = 1 << 4,
71        LT_DEFAULT      = 1 << 5,
72        LT_MBMODULE     = 1 << 6,
73        LT_ROOT         = 1 << 7,
74        LT_FALLBACK     = 1 << 8,
75        LT_KERNELARGS   = 1 << 9,
76        LT_BOOT         = 1 << 10,
77        LT_BOOTROOT     = 1 << 11,
78        LT_LBA          = 1 << 12,
79        LT_OTHER        = 1 << 13,
80        LT_GENERIC      = 1 << 14,
81        LT_ECHO    = 1 << 16,
82        LT_MENUENTRY    = 1 << 17,
83        LT_ENTRY_END    = 1 << 18,
84        LT_SET_VARIABLE = 1 << 19,
85        LT_UNKNOWN      = 1 << 20,
86    };
87    
88  struct singleLine {  struct singleLine {
89      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 104  struct singleEntry {
104    
105  #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 */
106    
107  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
108  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
109  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
110  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
111  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
112    #define NEED_MB      (1 << 4)
113    #define NEED_END     (1 << 5)
114    
115  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
116  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 74  struct keywordTypes { Line 119  struct keywordTypes {
119      char * key;      char * key;
120      enum lineType_e type;      enum lineType_e type;
121      char nextChar;      char nextChar;
122  } ;      char separatorChar;
123    };
124    
125    struct configFileInfo;
126    
127    typedef const char *(*findConfigFunc)(struct configFileInfo *);
128    typedef const int (*writeLineFunc)(struct configFileInfo *,
129     struct singleLine *line);
130    
131  struct configFileInfo {  struct configFileInfo {
132      char * defaultConfig;      char * defaultConfig;
133        findConfigFunc findConfig;
134        writeLineFunc writeLine;
135      struct keywordTypes * keywords;      struct keywordTypes * keywords;
136      int defaultIsIndex;      int defaultIsIndex;
137        int defaultIsVariable;
138      int defaultSupportSaved;      int defaultSupportSaved;
139      enum lineType_e entrySeparator;      enum lineType_e entryStart;
140        enum lineType_e entryEnd;
141      int needsBootPrefix;      int needsBootPrefix;
142      int argsInQuotes;      int argsInQuotes;
143      int maxTitleLength;      int maxTitleLength;
144      int titleBracketed;      int titleBracketed;
145        int titlePosition;
146        int mbHyperFirst;
147        int mbInitRdIsModule;
148        int mbConcatArgs;
149        int mbAllowExtraInitRds;
150  };  };
151    
152  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 155  struct keywordTypes grubKeywords[] = {
155      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
156      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
157      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
158      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
159      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
160        { "kernel",     LT_HYPER,       ' ' },
161      { NULL,    0, 0 },      { NULL,    0, 0 },
162  };  };
163    
164    const char *grubFindConfig(struct configFileInfo *cfi) {
165        static const char *configFiles[] = {
166     "/etc/grub.conf",
167     "/boot/grub/grub.conf",
168     "/boot/grub/menu.lst",
169     NULL
170        };
171        static int i = -1;
172    
173        if (i == -1) {
174     for (i = 0; configFiles[i] != NULL; i++) {
175        dbgPrintf("Checking \"%s\": ", configFiles[i]);
176        if (!access(configFiles[i], R_OK)) {
177     dbgPrintf("found\n");
178     return configFiles[i];
179        }
180        dbgPrintf("not found\n");
181     }
182        }
183        return configFiles[i];
184    }
185    
186  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
187      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
188      grubKeywords,    /* keywords */      .keywords = grubKeywords,
189      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
190      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
191      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
192      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
193      0,    /* argsInQuotes */      .mbHyperFirst = 1,
194      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
195      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
196    };
197    
198    struct keywordTypes grub2Keywords[] = {
199        { "menuentry",  LT_MENUENTRY,   ' ' },
200        { "}",          LT_ENTRY_END,   ' ' },
201        { "echo",       LT_ECHO,        ' ' },
202        { "set",        LT_SET_VARIABLE,' ', '=' },
203        { "root",       LT_BOOTROOT,    ' ' },
204        { "default",    LT_DEFAULT,     ' ' },
205        { "fallback",   LT_FALLBACK,    ' ' },
206        { "linux",      LT_KERNEL,      ' ' },
207        { "initrd",     LT_INITRD,      ' ', ' ' },
208        { "module",     LT_MBMODULE,    ' ' },
209        { "kernel",     LT_HYPER,       ' ' },
210        { NULL, 0, 0 },
211    };
212    
213    const char *grub2FindConfig(struct configFileInfo *cfi) {
214        static const char *configFiles[] = {
215     "/boot/grub/grub-efi.cfg",
216     "/boot/grub/grub.cfg",
217     NULL
218        };
219        static int i = -1;
220        static const char *grub_cfg = "/boot/grub/grub.cfg";
221    
222        if (i == -1) {
223     for (i = 0; configFiles[i] != NULL; i++) {
224        dbgPrintf("Checking \"%s\": ", configFiles[i]);
225        if (!access(configFiles[i], R_OK)) {
226     dbgPrintf("found\n");
227     return configFiles[i];
228        }
229     }
230        }
231    
232        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
233         * that isn't in grub1, and if it exists, return the config file path
234         * that they use. */
235        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
236     dbgPrintf("found\n");
237     return grub_cfg;
238        }
239    
240        dbgPrintf("not found\n");
241        return configFiles[i];
242    }
243    
244    int sizeOfSingleLine(struct singleLine * line) {
245      int i;
246      int count = 0;
247    
248      for (i = 0; i < line->numElements; i++) {
249        int indentSize = 0;
250    
251        count = count + strlen(line->elements[i].item);
252    
253        indentSize = strlen(line->elements[i].indent);
254        if (indentSize > 0)
255          count = count + indentSize;
256        else
257          /* be extra safe and add room for whitespaces */
258          count = count + 1;
259      }
260    
261      /* room for trailing terminator */
262      count = count + 1;
263    
264      return count;
265    }
266    
267    char *grub2ExtractTitle(struct singleLine * line) {
268        char * current;
269        char * current_indent;
270        int current_len;
271        int current_indent_len;
272        int i;
273    
274        /* bail out if line does not start with menuentry */
275        if (strcmp(line->elements[0].item, "menuentry"))
276          return NULL;
277    
278        i = 1;
279        current = line->elements[i].item;
280        current_len = strlen(current);
281    
282        /* if second word is quoted, strip the quotes and return single word */
283        if ((*current == '\'') && (*(current + current_len - 1) == '\'')) {
284          char *tmp;
285    
286          tmp = strdup(current);
287          *(tmp + current_len - 1) = '\0';
288          return ++tmp;
289        }
290    
291        /* if no quotes, return second word verbatim */
292        if (*current != '\'') {
293          return current;
294        }
295    
296        /* second element start with a quote, so we have to find the element
297         * whose last character is also quote (assuming it's the closing one) */
298        if (*current == '\'') {
299          int resultMaxSize;
300          char * result;
301    
302          resultMaxSize = sizeOfSingleLine(line);
303          result = malloc(resultMaxSize);
304          snprintf(result, resultMaxSize, "%s", ++current);
305    
306          i++;
307          for (; i < line->numElements; ++i) {
308     current = line->elements[i].item;
309     current_len = strlen(current);
310     current_indent = line->elements[i].indent;
311     current_indent_len = strlen(current_indent);
312    
313     strncat(result, current_indent, current_indent_len);
314     if (*(current + current_len - 1) != '\'') {
315      strncat(result, current, current_len);
316     } else {
317      strncat(result, current, current_len - 1);
318      break;
319     }
320          }
321          return result;
322        }
323    
324        return NULL;
325    }
326    
327    struct configFileInfo grub2ConfigType = {
328        .findConfig = grub2FindConfig,
329        .keywords = grub2Keywords,
330        .defaultIsIndex = 1,
331        .defaultSupportSaved = 0,
332        .defaultIsVariable = 1,
333        .entryStart = LT_MENUENTRY,
334        .entryEnd = LT_ENTRY_END,
335        .titlePosition = 1,
336        .needsBootPrefix = 1,
337        .mbHyperFirst = 1,
338        .mbInitRdIsModule = 1,
339        .mbAllowExtraInitRds = 1,
340  };  };
341    
342  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 370  struct keywordTypes yabootKeywords[] = {
370      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
371      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
372      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
373      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
374      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
375      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
376      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 390  struct keywordTypes liloKeywords[] = {
390      { NULL,    0, 0 },      { NULL,    0, 0 },
391  };  };
392    
393    struct keywordTypes eliloKeywords[] = {
394        { "label",    LT_TITLE,    '=' },
395        { "root",    LT_ROOT,    '=' },
396        { "default",    LT_DEFAULT,    '=' },
397        { "image",    LT_KERNEL,    '=' },
398        { "initrd",    LT_INITRD,    '=' },
399        { "append",    LT_KERNELARGS,  '=' },
400        { "vmm",    LT_HYPER,       '=' },
401        { NULL,    0, 0 },
402    };
403    
404  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
405      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
406      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 422  struct keywordTypes ziplKeywords[] = {
422      { NULL,         0, 0 },      { NULL,         0, 0 },
423  };  };
424    
425    struct keywordTypes extlinuxKeywords[] = {
426        { "label",    LT_TITLE,    ' ' },
427        { "root",    LT_ROOT,    ' ' },
428        { "default",    LT_DEFAULT,    ' ' },
429        { "kernel",    LT_KERNEL,    ' ' },
430        { "initrd",    LT_INITRD,      ' ', ',' },
431        { "append",    LT_KERNELARGS,  ' ' },
432        { "prompt",     LT_UNKNOWN,     ' ' },
433        { NULL,    0, 0 },
434    };
435    int useextlinuxmenu;
436  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
437      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
438      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
439      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
440      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
441      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
442      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
443  };  };
444    
445  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
446      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
447      liloKeywords,    /* keywords */      .keywords = liloKeywords,
448      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
449      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
450      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
451  };  };
452    
453  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
454      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
455      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
456      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
457      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
458      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
459      1,    /* needsBootPrefix */      .maxTitleLength = 15,
460      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
461  };  };
462    
463  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
464      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
465      siloKeywords,    /* keywords */      .keywords = siloKeywords,
466      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
467      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
468      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
469      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
470  };  };
471    
472  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
473      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
474      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
475      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
476      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
477      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
478      0,    /* needsBootPrefix */  };
479      1,    /* argsInQuotes */  
480      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
481      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
482        .keywords = extlinuxKeywords,
483        .entryStart = LT_TITLE,
484        .needsBootPrefix = 1,
485        .maxTitleLength = 255,
486        .mbAllowExtraInitRds = 1,
487  };  };
488    
489  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 498  struct grubConfig {
498      struct configFileInfo * cfi;      struct configFileInfo * cfi;
499  };  };
500    
501    blkid_cache blkid;
502    
503  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
504  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
505       const char * path, const char * prefix,       const char * path, const char * prefix,
506       int * index);       int * index);
 static char * strndup(char * from, int len);  
507  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
508  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
509    struct singleLine * lineDup(struct singleLine * line);
510  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
511  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
512       struct configFileInfo * cfi);       struct configFileInfo * cfi);
513  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
514         struct configFileInfo * cfi);         struct configFileInfo * cfi);
515  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
516    static void requote(struct singleLine *line, struct configFileInfo * cfi);
517  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
518      char * to;    const char * item, int insertHere,
519      struct configFileInfo * cfi);
520      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
521      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
522      to[len] = '\0';        struct configFileInfo * cfi);
523    static enum lineType_e getTypeByKeyword(char * keyword,
524      return to;   struct configFileInfo * cfi);
525  }  static struct singleLine * getLineByType(enum lineType_e type,
526     struct singleLine * line);
527    static int checkForExtLinux(struct grubConfig * config);
528    struct singleLine * addLineTmpl(struct singleEntry * entry,
529                                    struct singleLine * tmplLine,
530                                    struct singleLine * prevLine,
531                                    const char * val,
532     struct configFileInfo * cfi);
533    struct singleLine *  addLine(struct singleEntry * entry,
534                                 struct configFileInfo * cfi,
535                                 enum lineType_e type, char * defaultIndent,
536                                 const char * val);
537    
538  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
539  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 568  static char * sdupprintf(const char *for
568      return buf;      return buf;
569  }  }
570    
571    static struct keywordTypes * getKeywordByType(enum lineType_e type,
572          struct configFileInfo * cfi) {
573        struct keywordTypes * kw;
574        for (kw = cfi->keywords; kw->key; kw++) {
575     if (kw->type == type)
576        return kw;
577        }
578        return NULL;
579    }
580    
581    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
582        struct keywordTypes *kt = getKeywordByType(type, cfi);
583        if (kt)
584     return kt->key;
585        return "unknown";
586    }
587    
588    static char * getpathbyspec(char *device) {
589        if (!blkid)
590            blkid_get_cache(&blkid, NULL);
591    
592        return blkid_get_devname(blkid, device, NULL);
593    }
594    
595    static char * getuuidbydev(char *device) {
596        if (!blkid)
597     blkid_get_cache(&blkid, NULL);
598    
599        return blkid_get_tag_value(blkid, "UUID", device);
600    }
601    
602    static enum lineType_e getTypeByKeyword(char * keyword,
603     struct configFileInfo * cfi) {
604        struct keywordTypes * kw;
605        for (kw = cfi->keywords; kw->key; kw++) {
606     if (!strcmp(keyword, kw->key))
607        return kw->type;
608        }
609        return LT_UNKNOWN;
610    }
611    
612    static struct singleLine * getLineByType(enum lineType_e type,
613     struct singleLine * line) {
614        dbgPrintf("getLineByType(%d): ", type);
615        for (; line; line = line->next) {
616     dbgPrintf("%d:%s ", line->type,
617      line->numElements ? line->elements[0].item : "(empty)");
618     if (line->type & type) break;
619        }
620        dbgPrintf(line ? "\n" : " (failed)\n");
621        return line;
622    }
623    
624  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
625      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
626          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
627          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
628              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 634  static int isBracketedTitle(struct singl
634      return 0;      return 0;
635  }  }
636    
637  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
638                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
639      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
640   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;  
641  }  }
642    
643  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 688  static void lineInit(struct singleLine *
688      line->next = NULL;      line->next = NULL;
689  }  }
690    
691    struct singleLine * lineDup(struct singleLine * line) {
692        int i;
693        struct singleLine * newLine = malloc(sizeof(*newLine));
694    
695        newLine->indent = strdup(line->indent);
696        newLine->next = NULL;
697        newLine->type = line->type;
698        newLine->numElements = line->numElements;
699        newLine->elements = malloc(sizeof(*newLine->elements) *
700           newLine->numElements);
701    
702        for (i = 0; i < newLine->numElements; i++) {
703     newLine->elements[i].indent = strdup(line->elements[i].indent);
704     newLine->elements[i].item = strdup(line->elements[i].item);
705        }
706    
707        return newLine;
708    }
709    
710  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
711      int i;      int i;
712    
# Line 414  static int lineWrite(FILE * out, struct Line 732  static int lineWrite(FILE * out, struct
732      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
733    
734   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
735   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
736        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
737      }      }
738    
739      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 752  static int getNextLine(char ** bufPtr, s
752      char * chptr;      char * chptr;
753      int elementsAlloced = 0;      int elementsAlloced = 0;
754      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
755      int first = 1;      int first = 1;
     int i;  
756    
757      lineFree(line);      lineFree(line);
758    
# Line 489  static int getNextLine(char ** bufPtr, s Line 806  static int getNextLine(char ** bufPtr, s
806      if (!line->numElements)      if (!line->numElements)
807   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
808      else {      else {
809   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
810      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;  
               
811              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
812               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
813              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 843  static int getNextLine(char ** bufPtr, s
843   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
844   line->numElements = 0;   line->numElements = 0;
845      }      }
846     } else {
847     struct keywordTypes *kw;
848    
849     kw = getKeywordByType(line->type, cfi);
850    
851     /* space isn't the only separator, we need to split
852     * elements up more
853     */
854     if (!isspace(kw->separatorChar)) {
855        int i;
856        char indent[2] = "";
857        indent[0] = kw->separatorChar;
858        for (i = 1; i < line->numElements; i++) {
859     char *p;
860     int j;
861     int numNewElements;
862    
863     numNewElements = 0;
864     p = line->elements[i].item;
865     while (*p != '\0') {
866     if (*p == kw->separatorChar)
867     numNewElements++;
868     p++;
869     }
870     if (line->numElements + numNewElements >= elementsAlloced) {
871     elementsAlloced += numNewElements + 5;
872     line->elements = realloc(line->elements,
873        sizeof(*line->elements) * elementsAlloced);
874     }
875    
876     for (j = line->numElements; j > i; j--) {
877     line->elements[j + numNewElements] = line->elements[j];
878     }
879     line->numElements += numNewElements;
880    
881     p = line->elements[i].item;
882     while (*p != '\0') {
883    
884     while (*p != kw->separatorChar && *p != '\0') p++;
885     if (*p == '\0') {
886     break;
887     }
888    
889     free(line->elements[i].indent);
890     line->elements[i].indent = strdup(indent);
891     *p++ = '\0';
892     i++;
893     line->elements[i].item = strdup(p);
894     line->elements[i].indent = strdup("");
895     p = line->elements[i].item;
896     }
897        }
898     }
899   }   }
900      }      }
901    
# Line 595  static struct grubConfig * readConfig(co Line 959  static struct grubConfig * readConfig(co
959      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
960   }   }
961    
962   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
963      sawEntry = 1;      sawEntry = 1;
964      if (!entry) {      if (!entry) {
965   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 975  static struct grubConfig * readConfig(co
975      entry->next = NULL;      entry->next = NULL;
976   }   }
977    
978   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
979        int i;
980        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
981        dbgPrintf("%s", line->indent);
982        for (i = 0; i < line->numElements; i++)
983     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
984        dbgPrintf("\n");
985        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
986        if (kwType && line->numElements == 3 &&
987        !strcmp(line->elements[1].item, kwType->key)) {
988     dbgPrintf("Line sets default config\n");
989     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
990     defaultLine = line;
991        }
992     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
993      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
994      defaultLine = line;      defaultLine = line;
995    
996            } else if (line->type == LT_KERNEL) {
997        /* if by some freak chance this is multiboot and the "module"
998         * lines came earlier in the template, make sure to use LT_HYPER
999         * instead of LT_KERNEL now
1000         */
1001        if (entry->multiboot)
1002     line->type = LT_HYPER;
1003    
1004          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1005        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1006         * instead, now that we know this is a multiboot entry.
1007         * This only applies to grub, but that's the only place we
1008         * should find LT_MBMODULE lines anyway.
1009         */
1010        struct singleLine * l;
1011        for (l = entry->lines; l; l = l->next) {
1012     if (l->type == LT_HYPER)
1013        break;
1014     else if (l->type == LT_KERNEL) {
1015        l->type = LT_HYPER;
1016        break;
1017     }
1018        }
1019              entry->multiboot = 1;              entry->multiboot = 1;
1020    
1021     } else if (line->type == LT_HYPER) {
1022        entry->multiboot = 1;
1023    
1024   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1025      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1026      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1027    
1028   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1029      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1030      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 1049  static struct grubConfig * readConfig(co
1049      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1050      line->elements[1].item = buf;      line->elements[1].item = buf;
1051      line->numElements = 2;      line->numElements = 2;
1052    
1053   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1054      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1055         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 652  static struct grubConfig * readConfig(co Line 1059  static struct grubConfig * readConfig(co
1059   int last, len;   int last, len;
1060    
1061   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
1062      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1063     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1064    
1065   last = line->numElements - 1;   last = line->numElements - 1;
1066   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1067   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
1068      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1069      }      }
   
1070   }   }
1071    
1072   /* 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 1086  static struct grubConfig * readConfig(co
1086   movedLine = 1;   movedLine = 1;
1087   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1088   }   }
1089    
1090   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1091     which was moved, drop it. */     which was moved, drop it. */
1092   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 1102  static struct grubConfig * readConfig(co
1102   entry->lines = line;   entry->lines = line;
1103      else      else
1104   last->next = line;   last->next = line;
1105        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1106    
1107        /* we could have seen this outside of an entry... if so, we
1108         * ignore it like any other line we don't grok */
1109        if (line->type == LT_ENTRY_END && sawEntry)
1110     sawEntry = 0;
1111   } else {   } else {
1112      if (!cfg->theLines)      if (!cfg->theLines)
1113   cfg->theLines = line;   cfg->theLines = line;
1114      else {      else
1115   last->next = line;   last->next = line;
1116      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1117   }   }
1118    
1119   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1121  static struct grubConfig * readConfig(co
1121    
1122      free(incoming);      free(incoming);
1123    
1124        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1125      if (defaultLine) {      if (defaultLine) {
1126   if (cfi->defaultSupportSaved &&   if (cfi->defaultIsVariable) {
1127        char *value = defaultLine->elements[2].item;
1128        while (*value && (*value == '"' || *value == '\'' ||
1129        *value == ' ' || *value == '\t'))
1130     value++;
1131        cfg->defaultImage = strtol(value, &end, 10);
1132        while (*end && (*end == '"' || *end == '\'' ||
1133        *end == ' ' || *end == '\t'))
1134     end++;
1135        if (*end) cfg->defaultImage = -1;
1136     } else if (cfi->defaultSupportSaved &&
1137   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1138      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1139   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1154  static struct grubConfig * readConfig(co
1154                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1155                  }                  }
1156   i++;   i++;
1157     entry = NULL;
1158      }      }
1159    
1160      if (entry) cfg->defaultImage = i;      if (entry){
1161            cfg->defaultImage = i;
1162        }else{
1163            cfg->defaultImage = -1;
1164        }
1165   }   }
1166        } else {
1167            cfg->defaultImage = 0;
1168      }      }
1169    
1170      return cfg;      return cfg;
# Line 751  static void writeDefault(FILE * out, cha Line 1182  static void writeDefault(FILE * out, cha
1182   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1183      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1184   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1185      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1186      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1187     cfg->defaultImage);
1188        } else {
1189     fprintf(out, "%sdefault%s%d\n", indent, separator,
1190     cfg->defaultImage);
1191        }
1192   } else {   } else {
1193      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1194    
# Line 769  static void writeDefault(FILE * out, cha Line 1205  static void writeDefault(FILE * out, cha
1205    
1206      if (!entry) return;      if (!entry) return;
1207    
1208      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1209    
1210      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1211   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1239  static int writeConfig(struct grubConfig
1239      int rc;      int rc;
1240    
1241      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1242         directory to / */         directory to the dir of the symlink */
1243      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1244      do {      do {
1245   buf = alloca(len + 1);   buf = alloca(len + 1);
1246   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1247   if (rc == len) len += 256;   if (rc == len) len += 256;
1248      } while (rc == len);      } while (rc == len);
1249            
# Line 843  static int writeConfig(struct grubConfig Line 1278  static int writeConfig(struct grubConfig
1278      }      }
1279    
1280      line = cfg->theLines;      line = cfg->theLines;
1281        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1282      while (line) {      while (line) {
1283   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1284     line->numElements == 3 &&
1285     !strcmp(line->elements[1].item, defaultKw->key)) {
1286        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1287        needs &= ~MAIN_DEFAULT;
1288     } else if (line->type == LT_DEFAULT) {
1289      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1290      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1291   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1353  static int numEntries(struct grubConfig
1353      return i;      return i;
1354  }  }
1355    
1356    static char *findDiskForRoot()
1357    {
1358        int fd;
1359        char buf[65536];
1360        char *devname;
1361        char *chptr;
1362        int rc;
1363    
1364        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1365            fprintf(stderr, "grubby: failed to open %s: %s\n",
1366                    _PATH_MOUNTED, strerror(errno));
1367            return NULL;
1368        }
1369    
1370        rc = read(fd, buf, sizeof(buf) - 1);
1371        if (rc <= 0) {
1372            fprintf(stderr, "grubby: failed to read %s: %s\n",
1373                    _PATH_MOUNTED, strerror(errno));
1374            close(fd);
1375            return NULL;
1376        }
1377        close(fd);
1378        buf[rc] = '\0';
1379        chptr = buf;
1380    
1381        while (chptr && chptr != buf+rc) {
1382            devname = chptr;
1383    
1384            /*
1385             * The first column of a mtab entry is the device, but if the entry is a
1386             * special device it won't start with /, so move on to the next line.
1387             */
1388            if (*devname != '/') {
1389                chptr = strchr(chptr, '\n');
1390                if (chptr)
1391                    chptr++;
1392                continue;
1393            }
1394    
1395            /* Seek to the next space */
1396            chptr = strchr(chptr, ' ');
1397            if (!chptr) {
1398                fprintf(stderr, "grubby: error parsing %s: %s\n",
1399                        _PATH_MOUNTED, strerror(errno));
1400                return NULL;
1401            }
1402    
1403            /*
1404             * The second column of a mtab entry is the mount point, we are looking
1405             * for '/' obviously.
1406             */
1407            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1408                /*
1409                 * Move back 2, which is the first space after the device name, set
1410                 * it to \0 so strdup will just get the devicename.
1411                 */
1412                chptr -= 2;
1413                *chptr = '\0';
1414                return strdup(devname);
1415            }
1416    
1417            /* Next line */
1418            chptr = strchr(chptr, '\n');
1419            if (chptr)
1420                chptr++;
1421        }
1422    
1423        return NULL;
1424    }
1425    
1426    void printEntry(struct singleEntry * entry) {
1427        int i;
1428        struct singleLine * line;
1429    
1430        for (line = entry->lines; line; line = line->next) {
1431     fprintf(stderr, "DBG: %s", line->indent);
1432     for (i = 0; i < line->numElements; i++) {
1433     fprintf(stderr, "%s%s",
1434        line->elements[i].item, line->elements[i].indent);
1435     }
1436     fprintf(stderr, "\n");
1437        }
1438    }
1439    
1440    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1441    {
1442        va_list argp;
1443    
1444        if (!debug)
1445     return;
1446    
1447        va_start(argp, fmt);
1448        fprintf(stderr, "DBG: Image entry failed: ");
1449        vfprintf(stderr, fmt, argp);
1450        printEntry(entry);
1451        va_end(argp);
1452    }
1453    
1454    #define beginswith(s, c) ((s) && (s)[0] == (c))
1455    
1456    static int endswith(const char *s, char c)
1457    {
1458     int slen;
1459    
1460     if (!s && !s[0])
1461     return 0;
1462     slen = strlen(s) - 1;
1463    
1464     return s[slen] == c;
1465    }
1466    
1467  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1468    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1469      struct singleLine * line;      struct singleLine * line;
1470      char * fullName;      char * fullName;
1471      int i;      int i;
     struct stat sb, sb2;  
1472      char * dev;      char * dev;
     char * end;  
1473      char * rootspec;      char * rootspec;
1474        char * rootdev;
1475    
1476      line = entry->lines;      if (skipRemoved && entry->skip) {
1477      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1478         return 0;
1479      if (!line) return 0;      }
1480      if (skipRemoved && entry->skip) return 0;  
1481      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1482        if (!line) {
1483     notSuitablePrintf(entry, "no line found\n");
1484     return 0;
1485        }
1486        if (line->numElements < 2) {
1487     notSuitablePrintf(entry, "line has only %d elements\n",
1488        line->numElements);
1489     return 0;
1490        }
1491    
1492      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1493    
1494      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1495        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1496      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1497      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1498              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1499                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1500      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1501                line->elements[1].item + rootspec_offset);
1502        if (access(fullName, R_OK)) {
1503     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1504     return 0;
1505        }
1506      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1507   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1508      if (i < line->numElements) {      if (i < line->numElements) {
1509   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1510      } else {      } else {
1511   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1512   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1513    
1514   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1515      dev = line->elements[1].item;      dev = line->elements[1].item;
1516   } else {   } else {
1517              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1518      /* 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.
1519      line = entry->lines;       */
1520        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1521    
1522              /* failed to find one */              /* failed to find one */
1523              if (!line) return 0;              if (!line) {
1524     notSuitablePrintf(entry, "no line found\n");
1525     return 0;
1526                }
1527    
1528      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1529          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1530      if (i < line->numElements)      if (i < line->numElements)
1531          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1532      else {      else {
1533     notSuitablePrintf(entry, "no root= entry found\n");
1534   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1535          return 0;          return 0;
1536              }              }
1537   }   }
1538      }      }
1539    
1540      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1541   dev += 6;      if (!getpathbyspec(dev)) {
1542            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1543   /* check which device has this label */          return 0;
1544   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1545   if (!dev) return 0;   dev = getpathbyspec(dev);
1546    
1547        rootdev = findDiskForRoot();
1548        if (!rootdev) {
1549            notSuitablePrintf(entry, "can't find root device\n");
1550     return 0;
1551      }      }
1552    
1553      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1554   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1555      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1556      } else {          free(rootdev);
1557   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1558   if (*end) return 0;      }
1559    
1560        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1561            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1562     getuuidbydev(rootdev), getuuidbydev(dev));
1563     free(rootdev);
1564            return 0;
1565      }      }
     stat("/", &sb2);  
1566    
1567      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1568    
1569      return 1;      return 1;
1570  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1608  struct singleEntry * findEntryByPath(str
1608   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1609   if (!entry) return NULL;   if (!entry) return NULL;
1610    
1611   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1612   if (!line) return NULL;   if (!line) return NULL;
1613    
1614   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1650  struct singleEntry * findEntryByPath(str
1650      kernel += 6;      kernel += 6;
1651   }   }
1652    
1653   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1654      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1655    
1656        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1657    
1658      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1659                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1660          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1661                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1662                              kernel + strlen(prefix)))       checkType, line);
1663                      break;   if (!line) break;  /* not found in this entry */
1664              }  
1665                 if (line && line->numElements >= 2) {
1666              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1667              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1668                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1669                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1670                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1671                      if (!strcmp(line->elements[1].item  +   }
1672                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1673    
1674      i++;      /* make sure this entry has a kernel identifier; this skips
1675         * non-Linux boot entries (could find netbsd etc, though, which is
1676         * unfortunate)
1677         */
1678        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1679     break; /* found 'im! */
1680   }   }
1681    
1682   if (index) *index = i;   if (index) *index = i;
1683      }      }
1684    
     if (!entry) return NULL;  
   
     /* make sure this entry has a kernel identifier; this skips non-Linux  
        boot entries (could find netbsd etc, though, which is unfortunate) */  
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
     if (!line) {  
  if (!index) index = &i;  
  (*index)++;  
  return findEntryByPath(config, kernel, prefix, index);  
     }  
   
1685      return entry;      return entry;
1686  }  }
1687    
# Line 1286  void displayEntry(struct singleEntry * e Line 1846  void displayEntry(struct singleEntry * e
1846      char * root = NULL;      char * root = NULL;
1847      int i;      int i;
1848    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1849      printf("index=%d\n", index);      printf("index=%d\n", index);
1850    
1851        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1852        if (!line) {
1853            printf("non linux entry\n");
1854            return;
1855        }
1856    
1857      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1858    
1859      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1871  void displayEntry(struct singleEntry * e
1871   }   }
1872   printf("\"\n");   printf("\"\n");
1873      } else {      } else {
1874   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1875   if (line) {   if (line) {
1876      char * s;      char * s;
1877    
# Line 1334  void displayEntry(struct singleEntry * e Line 1895  void displayEntry(struct singleEntry * e
1895      }      }
1896    
1897      if (!root) {      if (!root) {
1898   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1899   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1900      root=line->elements[1].item;      root=line->elements[1].item;
1901      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1910  void displayEntry(struct singleEntry * e
1910   printf("root=%s\n", s);   printf("root=%s\n", s);
1911      }      }
1912    
1913      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1914    
1915      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1916   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1927  int parseSysconfigGrub(int * lbaPtr, cha
1927      char * start;      char * start;
1928      char * param;      char * param;
1929    
1930      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1931      if (!in) return 1;      if (!in) return 1;
1932    
1933      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1989  int displayInfo(struct grubConfig * conf
1989   return 1;   return 1;
1990      }      }
1991    
1992      /* 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
1993         be a better way */         be a better way */
1994      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1995   dumpSysconfigGrub();   dumpSysconfigGrub();
1996      } else {      } else {
1997   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1998   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1999      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2000   }   }
2001    
2002   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2003   if (line) printf("lba\n");   if (line) printf("lba\n");
2004      }      }
2005    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2014  int displayInfo(struct grubConfig * conf
2014      return 0;      return 0;
2015  }  }
2016    
2017    struct singleLine * addLineTmpl(struct singleEntry * entry,
2018     struct singleLine * tmplLine,
2019     struct singleLine * prevLine,
2020     const char * val,
2021     struct configFileInfo * cfi)
2022    {
2023        struct singleLine * newLine = lineDup(tmplLine);
2024    
2025        if (val) {
2026     /* override the inherited value with our own.
2027     * This is a little weak because it only applies to elements[1]
2028     */
2029     if (newLine->numElements > 1)
2030        removeElement(newLine, 1);
2031     insertElement(newLine, val, 1, cfi);
2032    
2033     /* but try to keep the rootspec from the template... sigh */
2034     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2035        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2036        if (rootspec != NULL) {
2037     free(newLine->elements[1].item);
2038     newLine->elements[1].item =
2039        sdupprintf("%s%s", rootspec, val);
2040        }
2041     }
2042        }
2043    
2044        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2045          newLine->elements[0].item : "");
2046    
2047        if (!entry->lines) {
2048     /* first one on the list */
2049     entry->lines = newLine;
2050        } else if (prevLine) {
2051     /* add after prevLine */
2052     newLine->next = prevLine->next;
2053     prevLine->next = newLine;
2054        }
2055    
2056        return newLine;
2057    }
2058    
2059  /* val may be NULL */  /* val may be NULL */
2060  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2061       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2062       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2063       char * val) {       const char * val) {
2064      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2065      int i;      struct keywordTypes * kw;
2066        struct singleLine tmpl;
2067    
2068      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2069   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2070      if (type != LT_TITLE || !cfi->titleBracketed)       */
2071          if (!cfi->keywords[i].key) abort();  
2072        if (type == LT_TITLE && cfi->titleBracketed) {
2073     /* we're doing a bracketed title (zipl) */
2074     tmpl.type = type;
2075     tmpl.numElements = 1;
2076     tmpl.elements = alloca(sizeof(*tmpl.elements));
2077     tmpl.elements[0].item = alloca(strlen(val)+3);
2078     sprintf(tmpl.elements[0].item, "[%s]", val);
2079     tmpl.elements[0].indent = "";
2080     val = NULL;
2081        } else if (type == LT_MENUENTRY) {
2082     char *lineend = "--class gnu-linux --class gnu --class os {";
2083     if (!val) {
2084        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2085        abort();
2086     }
2087     kw = getKeywordByType(type, cfi);
2088     if (!kw) {
2089        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2090        abort();
2091     }
2092     tmpl.indent = "";
2093     tmpl.type = type;
2094     tmpl.numElements = 3;
2095     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2096     tmpl.elements[0].item = kw->key;
2097     tmpl.elements[0].indent = alloca(2);
2098     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2099     tmpl.elements[1].item = (char *)val;
2100     tmpl.elements[1].indent = alloca(2);
2101     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2102     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2103     strcpy(tmpl.elements[2].item, lineend);
2104     tmpl.elements[2].indent = "";
2105        } else {
2106     kw = getKeywordByType(type, cfi);
2107     if (!kw) {
2108        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2109        abort();
2110     }
2111     tmpl.type = type;
2112     tmpl.numElements = val ? 2 : 1;
2113     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2114     tmpl.elements[0].item = kw->key;
2115     tmpl.elements[0].indent = alloca(2);
2116     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2117     if (val) {
2118        tmpl.elements[1].item = (char *)val;
2119        tmpl.elements[1].indent = "";
2120     }
2121        }
2122    
2123      /* 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
2124         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2125         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
2126         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2127         differently from the rest) */         differently from the rest) */
2128      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2129   line = entry->lines;   if (line->numElements) prev = line;
2130   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2131   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;  
2132      }      }
2133    
2134      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2135          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2136          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2137          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2138          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2139          line->elements[0].indent = malloc(2);   else
2140          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2141          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2142             if (menuEntry)
2143          if (val) {      tmpl.indent = "\t";
2144              line->elements[1].item = val;   else if (prev == entry->lines)
2145              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2146          }   else
2147      } 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("");  
2148      }      }
2149    
2150      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2151  }  }
2152    
2153  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2172  void removeLine(struct singleEntry * ent
2172      free(line);      free(line);
2173  }  }
2174    
2175    static int isquote(char q)
2176    {
2177        if (q == '\'' || q == '\"')
2178     return 1;
2179        return 0;
2180    }
2181    
2182    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2183    {
2184        struct singleLine newLine = {
2185     .indent = tmplLine->indent,
2186     .type = tmplLine->type,
2187     .next = tmplLine->next,
2188        };
2189        int firstQuotedItem = -1;
2190        int quoteLen = 0;
2191        int j;
2192        int element = 0;
2193        char *c;
2194    
2195        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2196        strcpy(c, tmplLine->elements[0].item);
2197        insertElement(&newLine, c, element++, cfi);
2198        free(c);
2199        c = NULL;
2200    
2201        for (j = 1; j < tmplLine->numElements; j++) {
2202     if (firstQuotedItem == -1) {
2203        quoteLen += strlen(tmplLine->elements[j].item);
2204        
2205        if (isquote(tmplLine->elements[j].item[0])) {
2206     firstQuotedItem = j;
2207            quoteLen += strlen(tmplLine->elements[j].indent);
2208        } else {
2209     c = malloc(quoteLen + 1);
2210     strcpy(c, tmplLine->elements[j].item);
2211     insertElement(&newLine, c, element++, cfi);
2212     free(c);
2213     quoteLen = 0;
2214        }
2215     } else {
2216        int itemlen = strlen(tmplLine->elements[j].item);
2217        quoteLen += itemlen;
2218        quoteLen += strlen(tmplLine->elements[j].indent);
2219        
2220        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2221     c = malloc(quoteLen + 1);
2222     c[0] = '\0';
2223     for (int i = firstQuotedItem; i < j+1; i++) {
2224        strcat(c, tmplLine->elements[i].item);
2225        strcat(c, tmplLine->elements[i].indent);
2226     }
2227     insertElement(&newLine, c, element++, cfi);
2228     free(c);
2229    
2230     firstQuotedItem = -1;
2231     quoteLen = 0;
2232        }
2233     }
2234        }
2235        while (tmplLine->numElements)
2236     removeElement(tmplLine, 0);
2237        if (tmplLine->elements)
2238     free(tmplLine->elements);
2239    
2240        tmplLine->numElements = newLine.numElements;
2241        tmplLine->elements = newLine.elements;
2242    }
2243    
2244    static void insertElement(struct singleLine * line,
2245      const char * item, int insertHere,
2246      struct configFileInfo * cfi)
2247    {
2248        struct keywordTypes * kw;
2249        char indent[2] = "";
2250    
2251        /* sanity check */
2252        if (insertHere > line->numElements) {
2253     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2254      insertHere, line->numElements);
2255     insertHere = line->numElements;
2256        }
2257    
2258        line->elements = realloc(line->elements, (line->numElements + 1) *
2259         sizeof(*line->elements));
2260        memmove(&line->elements[insertHere+1],
2261        &line->elements[insertHere],
2262        (line->numElements - insertHere) *
2263        sizeof(*line->elements));
2264        line->elements[insertHere].item = strdup(item);
2265    
2266        kw = getKeywordByType(line->type, cfi);
2267    
2268        if (line->numElements == 0) {
2269     indent[0] = '\0';
2270        } else if (insertHere == 0) {
2271     indent[0] = kw->nextChar;
2272        } else if (kw->separatorChar != '\0') {
2273     indent[0] = kw->separatorChar;
2274        } else {
2275     indent[0] = ' ';
2276        }
2277    
2278        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2279     /* move the end-of-line forward */
2280     line->elements[insertHere].indent =
2281        line->elements[insertHere-1].indent;
2282     line->elements[insertHere-1].indent = strdup(indent);
2283        } else {
2284     line->elements[insertHere].indent = strdup(indent);
2285        }
2286    
2287        line->numElements++;
2288    
2289        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2290          line->elements[0].item,
2291          line->elements[insertHere].item,
2292          line->elements[insertHere].indent,
2293          insertHere);
2294    }
2295    
2296    static void removeElement(struct singleLine * line, int removeHere) {
2297        int i;
2298    
2299        /* sanity check */
2300        if (removeHere >= line->numElements) return;
2301    
2302        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2303          removeHere, line->elements[removeHere].item);
2304    
2305        free(line->elements[removeHere].item);
2306    
2307        if (removeHere > 1) {
2308     /* previous argument gets this argument's post-indentation */
2309     free(line->elements[removeHere-1].indent);
2310     line->elements[removeHere-1].indent =
2311        line->elements[removeHere].indent;
2312        } else {
2313     free(line->elements[removeHere].indent);
2314        }
2315    
2316        /* now collapse the array, but don't bother to realloc smaller */
2317        for (i = removeHere; i < line->numElements - 1; i++)
2318     line->elements[i] = line->elements[i + 1];
2319    
2320        line->numElements--;
2321    }
2322    
2323  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2324      char * first, * second;      char * first, * second;
2325      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2342  int updateActualImage(struct grubConfig
2342      struct singleEntry * entry;      struct singleEntry * entry;
2343      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2344      int index = 0;      int index = 0;
2345      int i, j, k;      int i, k;
2346      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2347      const char ** arg;      const char ** arg;
2348      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2349      int firstElement;      int firstElement;
2350      int *usedElements, *usedArgs;      int *usedElements;
2351        int doreplace;
2352    
2353      if (!image) return 0;      if (!image) return 0;
2354    
# Line 1609  int updateActualImage(struct grubConfig Line 2375  int updateActualImage(struct grubConfig
2375   }   }
2376      }      }
2377    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2378    
2379      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2380   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2381    
2382      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2383   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2384    
2385      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2386    
2387      k = 0;   if (multibootArgs && !entry->multiboot)
2388      for (arg = newArgs; *arg; arg++)      continue;
2389          k++;  
2390      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2391     * LT_KERNELARGS, use that.  Otherwise use
2392     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2393     */
2394     if (useKernelArgs) {
2395        line = getLineByType(LT_KERNELARGS, entry->lines);
2396        if (!line) {
2397     /* no LT_KERNELARGS, need to add it */
2398     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2399           cfg->secondaryIndent, NULL);
2400        }
2401        firstElement = 1;
2402    
2403      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2404   index++;      line = getLineByType(LT_HYPER, entry->lines);
2405        if (!line) {
2406     /* a multiboot entry without LT_HYPER? */
2407     continue;
2408        }
2409        firstElement = 2;
2410    
2411   line = entry->lines;   } else {
2412   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2413   if (!line) continue;      if (!line) {
2414   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2415     continue;
2416          if (entry->multiboot && !multibootArgs) {      }
2417              /* 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;  
2418   }   }
2419    
2420   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2421      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2422      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2423     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2424        /* this is a multiboot entry, make sure there's
2425         * -- on the args line
2426         */
2427        for (i = firstElement; i < line->numElements; i++) {
2428     if (!strcmp(line->elements[i].item, "--"))
2429        break;
2430        }
2431        if (i == line->numElements) {
2432     /* assume all existing args are kernel args,
2433     * prepend -- to make it official
2434     */
2435     insertElement(line, "--", firstElement, cfg->cfi);
2436     i = firstElement;
2437        }
2438        if (!multibootArgs) {
2439     /* kernel args start after the -- */
2440     firstElement = i + 1;
2441        }
2442     } else if (cfg->cfi->mbConcatArgs) {
2443        /* this is a non-multiboot entry, remove hyper args */
2444        for (i = firstElement; i < line->numElements; i++) {
2445     if (!strcmp(line->elements[i].item, "--"))
2446        break;
2447        }
2448        if (i < line->numElements) {
2449     /* remove args up to -- */
2450     while (strcmp(line->elements[firstElement].item, "--"))
2451        removeElement(line, firstElement);
2452     /* remove -- */
2453     removeElement(line, firstElement);
2454        }
2455   }   }
2456    
2457          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2458    
2459          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2460   for (arg = newArgs; *arg; arg++) {  
2461              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2462      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2463     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2464        !strcmp(line->elements[i].item, "--"))
2465     {
2466        /* reached the end of hyper args, insert here */
2467        doreplace = 0;
2468        break;  
2469     }
2470                  if (usedElements[i])                  if (usedElements[i])
2471                      continue;                      continue;
2472   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2473                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2474      break;      break;
2475                  }                  }
2476              }              }
     chptr = strchr(*arg, '=');  
2477    
2478      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2479   /* replace */   /* direct replacement */
2480   free(line->elements[i].item);   free(line->elements[i].item);
2481   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("");  
  }  
2482    
2483   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2484   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2485      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2486   /* append */   if (rootLine) {
2487   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2488   (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(" ");  
2489   } else {   } else {
2490      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2491         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2492   }   }
2493        }
2494    
2495   line->numElements++;      else {
2496     /* insert/append */
2497     insertElement(line, *arg, i, cfg->cfi);
2498     usedElements = realloc(usedElements, line->numElements *
2499           sizeof(*usedElements));
2500     memmove(&usedElements[i + 1], &usedElements[i],
2501     line->numElements - i - 1);
2502     usedElements[i] = 1;
2503    
2504   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2505     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2506     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2507   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2508      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2509      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2510   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2511   }   }
2512      }      }
             k++;  
2513   }   }
2514    
2515          free(usedElements);          free(usedElements);
2516    
  /* 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? */  
2517   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2518      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2519   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2520        !strcmp(line->elements[i].item, "--"))
2521        /* reached the end of hyper args, stop here */
2522        break;
2523     if (!argMatch(line->elements[i].item, *arg)) {
2524        removeElement(line, i);
2525      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;  
2526   }   }
2527        }
2528   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2529        if (useRoot && !strncmp(*arg, "root=", 5)) {
2530   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2531      line->elements[j - 1] = line->elements[j];   if (rootLine)
2532        removeLine(entry, rootLine);
  line->numElements--;  
2533      }      }
2534   }   }
2535    
# Line 1760  int updateActualImage(struct grubConfig Line 2540  int updateActualImage(struct grubConfig
2540   }   }
2541      }      }
2542    
     free(usedArgs);  
2543      free(newArgs);      free(newArgs);
2544      free(oldArgs);      free(oldArgs);
2545    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2565  int updateImage(struct grubConfig * cfg,
2565      return rc;      return rc;
2566  }  }
2567    
2568    int updateInitrd(struct grubConfig * cfg, const char * image,
2569                     const char * prefix, const char * initrd) {
2570        struct singleEntry * entry;
2571        struct singleLine * line, * kernelLine, *endLine = NULL;
2572        int index = 0;
2573    
2574        if (!image) return 0;
2575    
2576        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2577            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2578            if (!kernelLine) continue;
2579    
2580            line = getLineByType(LT_INITRD, entry->lines);
2581            if (line)
2582                removeLine(entry, line);
2583            if (prefix) {
2584                int prefixLen = strlen(prefix);
2585                if (!strncmp(initrd, prefix, prefixLen))
2586                    initrd += prefixLen;
2587            }
2588     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2589     if (endLine)
2590        removeLine(entry, endLine);
2591            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2592            if (!line)
2593        return 1;
2594     if (endLine) {
2595        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2596                if (!line)
2597     return 1;
2598     }
2599    
2600            break;
2601        }
2602    
2603        return 0;
2604    }
2605    
2606  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2607      int fd;      int fd;
2608      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2626  int checkDeviceBootloader(const char * d
2626      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2627   return 0;   return 0;
2628    
2629      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2630   offset = boot[2] + 2;   offset = boot[2] + 2;
2631      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2632   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2633      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2634   offset = boot[1] + 2;        offset = boot[1] + 2;
2635            /*
2636     * it looks like grub, when copying stage1 into the mbr, patches stage1
2637     * right after the JMP location, replacing other instructions such as
2638     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2639     * different bytes.
2640     */
2641          if ((bootSect[offset + 1] == NOOP_OPCODE)
2642      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2643     offset = offset + 3;
2644          }
2645      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2646   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2647      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2783  int checkForLilo(struct grubConfig * con
2783      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2784  }  }
2785    
2786    int checkForGrub2(struct grubConfig * config) {
2787        if (!access("/etc/grub.d/", R_OK))
2788     return 2;
2789    
2790        return 1;
2791    }
2792    
2793  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2794      int fd;      int fd;
2795      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2810  int checkForGrub(struct grubConfig * con
2810      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2811   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2812   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2813     close(fd);
2814     return 1;
2815        }
2816        close(fd);
2817    
2818        return checkDeviceBootloader(boot, bootSect);
2819    }
2820    
2821    int checkForExtLinux(struct grubConfig * config) {
2822        int fd;
2823        unsigned char bootSect[512];
2824        char * boot;
2825        char executable[] = "/boot/extlinux/extlinux";
2826    
2827        printf("entered: checkForExtLinux()\n");
2828    
2829        if (parseSysconfigGrub(NULL, &boot))
2830     return 0;
2831    
2832        /* assume grub is not installed -- not an error condition */
2833        if (!boot)
2834     return 0;
2835    
2836        fd = open(executable, O_RDONLY);
2837        if (fd < 0)
2838     /* this doesn't exist if grub hasn't been installed */
2839     return 0;
2840    
2841        if (read(fd, bootSect, 512) != 512) {
2842     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2843     executable, strerror(errno));
2844   return 1;   return 1;
2845      }      }
2846      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2859  static char * getRootSpecifier(char * st
2859      return rootspec;      return rootspec;
2860  }  }
2861    
2862    static char * getInitrdVal(struct grubConfig * config,
2863       const char * prefix, struct singleLine *tmplLine,
2864       const char * newKernelInitrd,
2865       char ** extraInitrds, int extraInitrdCount)
2866    {
2867        char *initrdVal, *end;
2868        int i;
2869        size_t totalSize;
2870        size_t prefixLen;
2871        char separatorChar;
2872    
2873        prefixLen = strlen(prefix);
2874        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2875    
2876        for (i = 0; i < extraInitrdCount; i++) {
2877     totalSize += sizeof(separatorChar);
2878     totalSize += strlen(extraInitrds[i]) - prefixLen;
2879        }
2880    
2881        initrdVal = end = malloc(totalSize);
2882    
2883        end = stpcpy (end, newKernelInitrd + prefixLen);
2884    
2885        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2886        for (i = 0; i < extraInitrdCount; i++) {
2887     const char *extraInitrd;
2888     int j;
2889    
2890     extraInitrd = extraInitrds[i] + prefixLen;
2891     /* Don't add entries that are already there */
2892     if (tmplLine != NULL) {
2893        for (j = 2; j < tmplLine->numElements; j++)
2894     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2895        break;
2896    
2897        if (j != tmplLine->numElements)
2898     continue;
2899     }
2900    
2901     *end++ = separatorChar;
2902     end = stpcpy(end, extraInitrd);
2903        }
2904    
2905        return initrdVal;
2906    }
2907    
2908  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2909           const char * prefix,           const char * prefix,
2910   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2911   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2912     char ** extraInitrds, int extraInitrdCount,
2913                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2914      struct singleEntry * new;      struct singleEntry * new;
2915      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2916      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2917      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2918    
2919      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2920    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2944  int addNewKernel(struct grubConfig * con
2944      config->entries = new;      config->entries = new;
2945    
2946      /* copy/update from the template */      /* copy/update from the template */
2947      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2948        if (newKernelInitrd)
2949     needs |= NEED_INITRD;
2950      if (newMBKernel) {      if (newMBKernel) {
2951          needs |= KERNEL_MB;          needs |= NEED_MB;
2952          new->multiboot = 1;          new->multiboot = 1;
2953      }      }
2954    
2955      if (template) {      if (template) {
2956   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2957      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2958      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2959   indent = tmplLine->indent;   {
2960        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2961    
2962      /* skip comments */      /* skip comments */
2963      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2964      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2965      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2966    
2967      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2968      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2969     if (!template->multiboot && (needs & NEED_MB)) {
2970              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2971                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2972                  struct singleLine *l;       * hypervisor at the same time.
2973                  needs &= ~ KERNEL_MB;       */
2974        if (config->cfi->mbHyperFirst) {
2975                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2976                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2977                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2978                      newMBKernel + strlen(prefix));
2979                  tmplLine = lastLine;   /* set up for adding the kernel line */
2980                  if (!new->lines) {   free(tmplLine->indent);
2981                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2982                  } else {   needs &= ~NEED_MB;
2983                      newLine->next = l;      }
2984                      newLine = l;      if (needs & NEED_KERNEL) {
2985                  }   /* use addLineTmpl to preserve line elements,
2986                  continue;   * otherwise we could just call addLine.  Unfortunately
2987              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2988                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2989                  continue; /* don't need multiboot kernel here */   * change below.
2990              }   */
2991     struct keywordTypes * mbm_kw =
2992        getKeywordByType(LT_MBMODULE, config->cfi);
2993     if (mbm_kw) {
2994        tmplLine->type = LT_MBMODULE;
2995        free(tmplLine->elements[0].item);
2996        tmplLine->elements[0].item = strdup(mbm_kw->key);
2997     }
2998     newLine = addLineTmpl(new, tmplLine, newLine,
2999          newKernelPath + strlen(prefix), config->cfi);
3000     needs &= ~NEED_KERNEL;
3001        }
3002        if (needs & NEED_MB) { /* !mbHyperFirst */
3003     newLine = addLine(new, config->cfi, LT_HYPER,
3004      config->secondaryIndent,
3005      newMBKernel + strlen(prefix));
3006     needs &= ~NEED_MB;
3007        }
3008     } else if (needs & NEED_KERNEL) {
3009        newLine = addLineTmpl(new, tmplLine, newLine,
3010      newKernelPath + strlen(prefix), config->cfi);
3011        needs &= ~NEED_KERNEL;
3012     }
3013    
3014      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3015   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3016   new->lines = newLine;   if (needs & NEED_MB) {
3017      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3018   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3019   newLine = newLine->next;      needs &= ~NEED_MB;
3020      }   }
3021    
3022        } else if (tmplLine->type == LT_MBMODULE &&
3023           tmplLine->numElements >= 2) {
3024     if (new->multiboot) {
3025        if (needs & NEED_KERNEL) {
3026     newLine = addLineTmpl(new, tmplLine, newLine,
3027          newKernelPath +
3028          strlen(prefix), config->cfi);
3029     needs &= ~NEED_KERNEL;
3030        } else if (config->cfi->mbInitRdIsModule &&
3031           (needs & NEED_INITRD)) {
3032     char *initrdVal;
3033     initrdVal = getInitrdVal(config, prefix, tmplLine,
3034     newKernelInitrd, extraInitrds,
3035     extraInitrdCount);
3036     newLine = addLineTmpl(new, tmplLine, newLine,
3037          initrdVal, config->cfi);
3038     free(initrdVal);
3039     needs &= ~NEED_INITRD;
3040        }
3041     } else if (needs & NEED_KERNEL) {
3042        /* template is multi but new is not,
3043         * insert the kernel in the first module slot
3044         */
3045        tmplLine->type = LT_KERNEL;
3046        free(tmplLine->elements[0].item);
3047        tmplLine->elements[0].item =
3048     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3049        newLine = addLineTmpl(new, tmplLine, newLine,
3050      newKernelPath + strlen(prefix), config->cfi);
3051        needs &= ~NEED_KERNEL;
3052     } else if (needs & NEED_INITRD) {
3053        char *initrdVal;
3054        /* template is multi but new is not,
3055         * insert the initrd in the second module slot
3056         */
3057        tmplLine->type = LT_INITRD;
3058        free(tmplLine->elements[0].item);
3059        tmplLine->elements[0].item =
3060     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3061        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3062        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3063        free(initrdVal);
3064        needs &= ~NEED_INITRD;
3065     }
3066    
     newLine->indent = strdup(tmplLine->indent);  
     newLine->next = NULL;  
     newLine->type = tmplLine->type;  
     newLine->numElements = tmplLine->numElements;  
     newLine->elements = malloc(sizeof(*newLine->elements) *  
     newLine->numElements);  
     for (i = 0; i < newLine->numElements; i++) {  
  newLine->elements[i].item = strdup(tmplLine->elements[i].item);  
  newLine->elements[i].indent =  
  strdup(tmplLine->elements[i].indent);  
     }  
   
             lastLine = tmplLine;  
     if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {  
                 char * repl;  
                 if (!template->multiboot) {  
                     needs &= ~KERNEL_KERNEL;  
                     repl = newKernelPath;  
                 } else {  
                     needs &= ~KERNEL_MB;  
                     repl = newMBKernel;  
                 }  
                 if (new->multiboot && !template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("module");  
                     newLine->type = LT_MBMODULE;  
                 }  
  free(newLine->elements[1].item);  
                 rootspec = getRootSpecifier(tmplLine->elements[1].item);  
                 if (rootspec != NULL) {  
                     newLine->elements[1].item = sdupprintf("%s%s",  
                                                            rootspec,  
                                                            repl +  
                                                            strlen(prefix));  
                 } else {  
                     newLine->elements[1].item = strdup(repl +  
                                                        strlen(prefix));  
                 }  
             } else if (tmplLine->type == LT_MBMODULE &&  
                        tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {  
                 needs &= ~KERNEL_KERNEL;  
                 if (!new->multiboot && template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("kernel");  
                     newLine->type = LT_KERNEL;  
                 }  
  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));  
                 }  
3067      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3068      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3069   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3070   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3071                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3072                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3073                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3074                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3075                  }       */
3076                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3077                  if (rootspec != NULL) {   char *initrdVal;
3078                      newLine->elements[1].item = sdupprintf("%s%s",  
3079                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3080                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3081                                                             strlen(prefix));    config->secondaryIndent,
3082                  } else {    initrdVal);
3083                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3084                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3085                  }      }
3086              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3087                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3088   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3089                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3090                      free(newLine->elements[0].item);      free(initrdVal);
3091                      newLine->elements[0].item = strdup("initrd");      needs &= ~NEED_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;  
   
  for (i = 1; i < newLine->numElements; i++) {  
     free(newLine->elements[i].item);  
     free(newLine->elements[i].indent);  
3092   }   }
3093    
3094   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3095   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3096   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3097     char *nkt = malloc(strlen(newKernelTitle)+3);
3098     strcpy(nkt, "'");
3099     strcat(nkt, newKernelTitle);
3100     strcat(nkt, "'");
3101     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3102     free(nkt);
3103     needs &= ~NEED_TITLE;
3104      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3105                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3106                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3107                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3108                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3109                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3110                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3111                                             newLine->numElements);     config->cfi->titleBracketed) {
3112        /* addLineTmpl doesn't handle titleBracketed */
3113                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3114                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3115                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3116                  newLine->numElements = 1;   }
3117              }      } else if (tmplLine->type == LT_ECHO) {
3118        requote(tmplLine, config->cfi);
3119        static const char *prefix = "'Loading ";
3120        if (tmplLine->numElements > 1 &&
3121        strstr(tmplLine->elements[1].item, prefix) &&
3122        masterLine->next && masterLine->next->type == LT_KERNEL) {
3123     char *newTitle = malloc(strlen(prefix) +
3124     strlen(newKernelTitle) + 2);
3125    
3126     strcpy(newTitle, prefix);
3127     strcat(newTitle, newKernelTitle);
3128     strcat(newTitle, "'");
3129     newLine = addLine(new, config->cfi, LT_ECHO,
3130     tmplLine->indent, newTitle);
3131     free(newTitle);
3132        } else {
3133     /* pass through other lines from the template */
3134     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3135     config->cfi);
3136        }
3137        } else {
3138     /* pass through other lines from the template */
3139     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3140        }
3141   }   }
3142    
3143      } else {      } else {
3144   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3145      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3146     */
3147     switch (config->cfi->entryStart) {
3148        case LT_KERNEL:
3149     if (new->multiboot && config->cfi->mbHyperFirst) {
3150        /* fall through to LT_HYPER */
3151     } else {
3152        newLine = addLine(new, config->cfi, LT_KERNEL,
3153          config->primaryIndent,
3154          newKernelPath + strlen(prefix));
3155        needs &= ~NEED_KERNEL;
3156        break;
3157     }
3158    
3159        case LT_HYPER:
3160     newLine = addLine(new, config->cfi, LT_HYPER,
3161      config->primaryIndent,
3162      newMBKernel + strlen(prefix));
3163     needs &= ~NEED_MB;
3164   break;   break;
         }  
3165    
3166   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3167      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3168       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3169       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3170      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3171       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3172      default:        config->primaryIndent, nkt);
3173                  /* zipl strikes again */   free(nkt);
3174                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3175                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3176                      chptr = newKernelTitle;   break;
3177                      type = LT_TITLE;      }
3178                      break;      case LT_TITLE:
3179                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3180                      abort();   char * templabel;
3181                  }   int x = 0, y = 0;
3182   }  
3183     templabel = strdup(newKernelTitle);
3184     while( templabel[x]){
3185     if( templabel[x] == ' ' ){
3186     y = x;
3187     while( templabel[y] ){
3188     templabel[y] = templabel[y+1];
3189     y++;
3190     }
3191     }
3192     x++;
3193     }
3194     newLine = addLine(new, config->cfi, LT_TITLE,
3195      config->primaryIndent, templabel);
3196     free(templabel);
3197     }else{
3198     newLine = addLine(new, config->cfi, LT_TITLE,
3199      config->primaryIndent, newKernelTitle);
3200     }
3201     needs &= ~NEED_TITLE;
3202     break;
3203    
3204   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3205   new->lines = newLine;   abort();
3206     }
3207      }      }
3208    
3209      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3210          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3211              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3212                                config->secondaryIndent,       */
3213                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3214          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3215              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3216                                config->secondaryIndent,    newKernelTitle);
3217                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3218          /* don't need to check for title as it's guaranteed to have been      }
3219           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3220           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3221          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3222              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3223                                config->secondaryIndent,   needs &= ~NEED_MB;
3224                                newKernelInitrd + strlen(prefix));      }
3225      } else {      if (needs & NEED_KERNEL) {
3226          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3227              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3228                                config->secondaryIndent,        config->cfi)) ?
3229                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3230          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3231              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3232                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3233                                newKernelTitle);      }
3234          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3235              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3236                                config->secondaryIndent,    config->secondaryIndent,
3237                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3238     needs &= ~NEED_MB;
3239        }
3240        if (needs & NEED_INITRD) {
3241     char *initrdVal;
3242     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3243     newLine = addLine(new, config->cfi,
3244      (new->multiboot && getKeywordByType(LT_MBMODULE,
3245          config->cfi)) ?
3246      LT_MBMODULE : LT_INITRD,
3247      config->secondaryIndent,
3248      initrdVal);
3249     free(initrdVal);
3250     needs &= ~NEED_INITRD;
3251        }
3252        if (needs & NEED_END) {
3253     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3254     config->secondaryIndent, NULL);
3255     needs &= ~NEED_END;
3256        }
3257    
3258        if (needs) {
3259     printf(_("grubby: needs=%d, aborting\n"), needs);
3260     abort();
3261      }      }
3262    
3263      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3266  int addNewKernel(struct grubConfig * con
3266      return 0;      return 0;
3267  }  }
3268    
3269    static void traceback(int signum)
3270    {
3271        void *array[40];
3272        size_t size;
3273    
3274        signal(SIGSEGV, SIG_DFL);
3275        memset(array, '\0', sizeof (array));
3276        size = backtrace(array, 40);
3277    
3278        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3279                (unsigned long)size);
3280        backtrace_symbols_fd(array, size, STDERR_FILENO);
3281        exit(1);
3282    }
3283    
3284  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3285      poptContext optCon;      poptContext optCon;
3286      char * grubConfig = NULL;      const char * grubConfig = NULL;
3287      char * outputFile = NULL;      char * outputFile = NULL;
3288      int arg = 0;      int arg = 0;
3289      int flags = 0;      int flags = 0;
3290      int badImageOkay = 0;      int badImageOkay = 0;
3291        int configureGrub2 = 0;
3292      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3293      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3294        int configureExtLinux = 0;
3295      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3296        int extraInitrdCount = 0;
3297      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3298      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3299      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3309  int main(int argc, const char ** argv) {
3309      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3310      char * removeArgs = NULL;      char * removeArgs = NULL;
3311      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3312        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3313      const char * chptr = NULL;      const char * chptr = NULL;
3314      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3315      struct grubConfig * config;      struct grubConfig * config;
3316      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3317      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3318      int displayDefault = 0;      int displayDefault = 0;
3319        int displayDefaultIndex = 0;
3320        int displayDefaultTitle = 0;
3321      struct poptOption options[] = {      struct poptOption options[] = {
3322   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3323      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2335  int main(int argc, const char ** argv) { Line 3348  int main(int argc, const char ** argv) {
3348        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3349        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3350        "template"), NULL },        "template"), NULL },
3351     { "debug", 0, 0, &debug, 0,
3352        _("print debugging information for failures") },
3353   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3354      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3355     { "default-index", 0, 0, &displayDefaultIndex, 0,
3356        _("display the index of the default kernel") },
3357     { "default-title", 0, 0, &displayDefaultTitle, 0,
3358        _("display the title of the default kernel") },
3359   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3360      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3361     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3362        _("configure extlinux bootloader (from syslinux)") },
3363   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3364      _("configure grub bootloader") },      _("configure grub bootloader") },
3365     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3366        _("configure grub2 bootloader") },
3367   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3368      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3369      _("kernel-path") },      _("kernel-path") },
3370   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3371      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3372     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3373        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3374   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3375      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3376   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3407  int main(int argc, const char ** argv) {
3407   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3408      };      };
3409    
3410        useextlinuxmenu=0;
3411    
3412        signal(SIGSEGV, traceback);
3413    
3414      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3415      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3416    
# Line 2391  int main(int argc, const char ** argv) { Line 3420  int main(int argc, const char ** argv) {
3420      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3421      exit(0);      exit(0);
3422      break;      break;
3423      case 'i':
3424        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3425         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3426        } else {
3427     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3428     return 1;
3429        }
3430        break;
3431   }   }
3432      }      }
3433    
# Line 2406  int main(int argc, const char ** argv) { Line 3443  int main(int argc, const char ** argv) {
3443   return 1;   return 1;
3444      }      }
3445    
3446      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3447   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3448     configureExtLinux ) > 1) {
3449   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3450   return 1;   return 1;
3451      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3452   fprintf(stderr,   fprintf(stderr,
3453      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3454   return 1;   return 1;
3455        } else if (configureGrub2) {
3456     cfi = &grub2ConfigType;
3457      } else if (configureLilo) {      } else if (configureLilo) {
3458   cfi = &liloConfigType;   cfi = &liloConfigType;
3459      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3466  int main(int argc, const char ** argv) {
3466          cfi = &siloConfigType;          cfi = &siloConfigType;
3467      } else if (configureZipl) {      } else if (configureZipl) {
3468          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3469        } else if (configureExtLinux) {
3470     cfi = &extlinuxConfigType;
3471     useextlinuxmenu=1;
3472      }      }
3473    
3474      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3483  int main(int argc, const char ** argv) {
3483        #elif __s390x__        #elif __s390x__
3484          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3485        #else        #else
3486   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3487        cfi = &grub2ConfigType;
3488     else
3489        cfi = &grubConfigType;
3490        #endif        #endif
3491      }      }
3492    
3493      if (!grubConfig)      if (!grubConfig) {
3494   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3495        grubConfig = cfi->findConfig(cfi);
3496     if (!grubConfig)
3497        grubConfig = cfi->defaultConfig;
3498        }
3499    
3500      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3501    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3502    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3503   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3504    "specified option"));    "specified option"));
3505   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3515  int main(int argc, const char ** argv) {
3515      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3516   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3517   return 1;   return 1;
3518      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3519    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3520    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3521   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3522   return 1;   return 1;
3523      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3542  int main(int argc, const char ** argv) {
3542   defaultKernel = NULL;   defaultKernel = NULL;
3543      }      }
3544    
3545      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3546   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3547   "is used\n"));   "is used\n"));
3548   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3550  int main(int argc, const char ** argv) {
3550    
3551      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3552   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3553          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3554   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3555   return 1;   return 1;
3556      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3570  int main(int argc, const char ** argv) {
3570   bootPrefix = "";   bootPrefix = "";
3571      }      }
3572    
3573        if (!cfi->mbAllowExtraInitRds &&
3574     extraInitrdCount > 0) {
3575     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3576     return 1;
3577        }
3578    
3579      if (bootloaderProbe) {      if (bootloaderProbe) {
3580   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3581   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3582    
3583   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3584      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3585        gconfig = readConfig(grub2config, &grub2ConfigType);
3586        if (!gconfig)
3587     gr2c = 1;
3588        else
3589     gr2c = checkForGrub2(gconfig);
3590     }
3591    
3592     const char *grubconfig = grubFindConfig(&grubConfigType);
3593     if (!access(grubconfig, F_OK)) {
3594        gconfig = readConfig(grubconfig, &grubConfigType);
3595      if (!gconfig)      if (!gconfig)
3596   grc = 1;   grc = 1;
3597      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3606  int main(int argc, const char ** argv) {
3606   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3607   }   }
3608    
3609   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3610        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3611        if (!lconfig)
3612     erc = 1;
3613        else
3614     erc = checkForExtLinux(lconfig);
3615     }
3616    
3617     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3618    
3619   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3620     if (gr2c == 2) printf("grub2\n");
3621   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3622     if (erc == 2) printf("extlinux\n");
3623    
3624   return 0;   return 0;
3625      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3637  int main(int argc, const char ** argv) {
3637   if (!entry) return 0;   if (!entry) return 0;
3638   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3639    
3640   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3641   if (!line) return 0;   if (!line) return 0;
3642    
3643          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3645  int main(int argc, const char ** argv) {
3645                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3646    
3647   return 0;   return 0;
3648    
3649        } else if (displayDefaultTitle) {
3650     struct singleLine * line;
3651     struct singleEntry * entry;
3652    
3653     if (config->defaultImage == -1) return 0;
3654     entry = findEntryByIndex(config, config->defaultImage);
3655     if (!entry) return 0;
3656    
3657     if (!configureGrub2) {
3658      line = getLineByType(LT_TITLE, entry->lines);
3659      if (!line) return 0;
3660      printf("%s\n", line->elements[1].item);
3661    
3662     } else {
3663      char * title;
3664    
3665      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3666      line = getLineByType(LT_MENUENTRY, entry->lines);
3667      if (!line) return 0;
3668      title = grub2ExtractTitle(line);
3669      if (title)
3670        printf("%s\n", title);
3671     }
3672     return 0;
3673    
3674        } else if (displayDefaultIndex) {
3675            if (config->defaultImage == -1) return 0;
3676            printf("%i\n", config->defaultImage);
3677    
3678      } else if (kernelInfo)      } else if (kernelInfo)
3679   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3680    
# Line 2585  int main(int argc, const char ** argv) { Line 3690  int main(int argc, const char ** argv) {
3690      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3691      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3692                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3693        if (updateKernelPath && newKernelInitrd) {
3694                if (updateInitrd(config, updateKernelPath, bootPrefix,
3695                                 newKernelInitrd)) return 1;
3696        }
3697      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3698                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3699                         extraInitrds, extraInitrdCount,
3700                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3701            
3702    
# Line 2597  int main(int argc, const char ** argv) { Line 3707  int main(int argc, const char ** argv) {
3707      }      }
3708    
3709      if (!outputFile)      if (!outputFile)
3710   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3711    
3712      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3713  }  }

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