diff --git a/SOURCES/0001-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch b/SOURCES/0001-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch deleted file mode 100644 index 4e31618..0000000 --- a/SOURCES/0001-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch +++ /dev/null @@ -1,123 +0,0 @@ -From b9a37e249bf279ceb0b63ad4676f03d11796cfc9 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 26 Oct 2015 14:22:39 -0400 -Subject: [PATCH] Always do the "rungrubby --debug" after the normal kernel on - install. - -This way the during an update, the right kernel is picked as "default" -for the command line arguments. - -Related: rhbz#1212128 - -Signed-off-by: Peter Jones ---- - new-kernel-pkg | 20 ++++++++++---------- - 1 file changed, 10 insertions(+), 10 deletions(-) - -diff --git a/new-kernel-pkg b/new-kernel-pkg -index 9f56c47..9574dbb 100755 ---- a/new-kernel-pkg -+++ b/new-kernel-pkg -@@ -243,8 +243,8 @@ install() { - --args=\"root=$rootdevice $kernargs \$debugargs\" \ - --remove-kernel=\"TITLE=$title\$debugtitle\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} $makedefault -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby for grub 0.97" - fi -@@ -257,8 +257,8 @@ install() { - ${mbargs:+--mbargs=\"$mbargs\"} \ - --args=\"root=$rootdevice $kernargs \$debugargs\" \ - --remove-kernel=\"TITLE=$title\$debugtitle\"" -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} $makedefault -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby for grub 2" - fi -@@ -272,8 +272,8 @@ install() { - ${mbargs:+--mbargs=\"$mbargs\"} \ - --args=\"root=$rootdevice $kernargs \$debugargs\" \ - --remove-kernel=\"TITLE=$title\$debugtitle\"" -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} $makedefault -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby for grub 2 with UEFI" - fi -@@ -288,8 +288,8 @@ install() { - --args=\"root=$rootdevice $kernargs \$debugargs\" \ - --remove-kernel=\"TITLE=$version\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} $makedefault -+ rungrubby --debug ${ARGS} - if [ -n "$runLilo" ]; then - [ -n "$verbose" ] && echo "running $lilo" - if [ ! -x $lilo ] ; then -@@ -313,8 +313,8 @@ install() { - --args=\"root=$rootdevice $kernargs \$debugargs\" \ - --remove-kernel=\"TITLE=$title\$debugtitle\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} $makedefault -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby for extlinux" - fi -@@ -480,8 +480,8 @@ update() { - ${mbkernel:+--add-multiboot=\"$mbkernel\"} \ - --title=\"$title\$debugtitle\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby" - fi -@@ -493,8 +493,8 @@ update() { - ${removeargs:+--remove-args=\"$removeargs\"} \ - --title=\"$title\$debugtitle\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby" - fi -@@ -506,8 +506,8 @@ update() { - ${removeargs:+--remove-args=\"$removeargs\"} \ - --title=\"$title\$debugtitle\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby" - fi -@@ -519,8 +519,8 @@ update() { - ${removeargs:+--remove-args=\"$removeargs\"} \ - --title=\"$title\$debugtitle\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} -+ rungrubby --debug ${ARGS} - - if [ -n "$runLilo" ]; then - [ -n "$verbose" ] && echo "running $lilo" -@@ -571,8 +571,8 @@ update() { - ${removeargs:+--remove-args=\"$removeargs\"} \ - --title=\"$title\$debugtitle\"" - -- rungrubby --debug ${ARGS} - rungrubby ${ARGS} -+ rungrubby --debug ${ARGS} - else - [ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby" - fi --- -2.5.0 - diff --git a/SOURCES/0001-Don-t-leak-from-one-extractTitle-call.patch b/SOURCES/0001-Don-t-leak-from-one-extractTitle-call.patch deleted file mode 100644 index 6489935..0000000 --- a/SOURCES/0001-Don-t-leak-from-one-extractTitle-call.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 7713f8e23e326dcf1258a715e2554a4bf53dec59 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 2 Jul 2015 16:26:59 -0400 -Subject: [PATCH] Don't leak from one extractTitle() call. - -Found by coverity. - -Signed-off-by: Peter Jones ---- - grubby.c | 27 +++++++++++++++++---------- - 1 file changed, 17 insertions(+), 10 deletions(-) - -diff --git a/grubby.c b/grubby.c -index 0bb4869..70477ba 100644 ---- a/grubby.c -+++ b/grubby.c -@@ -1510,13 +1510,14 @@ static struct grubConfig * readConfig(const char * inName, - return cfg; - } - --static void writeDefault(FILE * out, char * indent, -+static void writeDefault(FILE * out, char * indent, - char * separator, struct grubConfig * cfg) { - struct singleEntry * entry; - struct singleLine * line; - int i; - -- if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) return; -+ if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) -+ return; - - if (cfg->defaultImage == DEFAULT_SAVED) - fprintf(out, "%sdefault%ssaved\n", indent, separator); -@@ -1540,34 +1541,40 @@ static void writeDefault(FILE * out, char * indent, - fprintf(out, "%sset default=\"%d\"\n", indent, - cfg->defaultImage); - } else { -- fprintf(out, "%sdefault%s%d\n", indent, separator, -+ fprintf(out, "%sdefault%s%d\n", indent, separator, - cfg->defaultImage); - } - } else { - int image = cfg->defaultImage; - - entry = cfg->entries; -- while (entry && entry->skip) entry = entry->next; -+ while (entry && entry->skip) -+ entry = entry->next; - - i = 0; - while (entry && i < image) { - entry = entry->next; - -- while (entry && entry->skip) entry = entry->next; -+ while (entry && entry->skip) -+ entry = entry->next; - i++; - } - -- if (!entry) return; -+ if (!entry) -+ return; - - line = getLineByType(LT_TITLE, entry->lines); - - if (line && line->numElements >= 2) -- fprintf(out, "%sdefault%s%s\n", indent, separator, -+ fprintf(out, "%sdefault%s%s\n", indent, separator, - line->elements[1].item); -- else if (line && (line->numElements == 1) && -+ else if (line && (line->numElements == 1) && - cfg->cfi->titleBracketed) { -- fprintf(out, "%sdefault%s%s\n", indent, separator, -- extractTitle(cfg, line)); -+ char *title = extractTitle(cfg, line); -+ if (title) { -+ fprintf(out, "%sdefault%s%s\n", indent, separator, title); -+ free(title); -+ } - } - } - } --- -2.4.3 - diff --git a/SOURCES/0001-Fix-some-coverity-concerns.patch b/SOURCES/0001-Fix-some-coverity-concerns.patch deleted file mode 100644 index a00bdde..0000000 --- a/SOURCES/0001-Fix-some-coverity-concerns.patch +++ /dev/null @@ -1,613 +0,0 @@ -From 916d5770b5c8fb87503a99f98c13a5232a7dafbf Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 10 Sep 2015 10:13:15 -0400 -Subject: [PATCH] Fix some coverity concerns... - -While checking on coverity's concern with kwcmp() having a loop it -really didn't need, I discovered another problem with the fix here that -made spaces not work right in grub2 variable assignment. So here's a -new version of the fix, and yet another test case. - -Resolves: rhbz#1152550 - -Signed-off-by: Peter Jones ---- - grubby.c | 204 ++++++++++++++++++++++++++++++++++++----------- - test.sh | 6 ++ - test/grub2.17 | 156 ++++++++++++++++++++++++++++++++++++ - test/results/add/g2-1.17 | 170 +++++++++++++++++++++++++++++++++++++++ - 4 files changed, 490 insertions(+), 46 deletions(-) - create mode 100644 test/grub2.17 - create mode 100644 test/results/add/g2-1.17 - -diff --git a/grubby.c b/grubby.c -index d66c1c5..2a6eedb 100644 ---- a/grubby.c -+++ b/grubby.c -@@ -751,28 +751,30 @@ static char *sdupprintf(const char *format, ...) - static inline int - kwcmp(struct keywordTypes *kw, const char * label, int case_insensitive) - { -- int kwl = strlen(kw->key); -- int ll = strlen(label); -- int rc; -- int (*snc)(const char *s1, const char *s2, size_t n) = -- case_insensitive ? strncasecmp : strncmp; -- int (*sc)(const char *s1, const char *s2) = -- case_insensitive ? strcasecmp : strcmp; -- -- rc = snc(kw->key, label, kwl); -- if (rc) -- return rc; -- -- for (int i = kwl; i < ll; i++) { -- if (isspace(label[i])) -- return 0; -- if (kw->separatorChar && label[i] == kw->separatorChar) -- return 0; -- else if (kw->nextChar && label[i] == kw->nextChar) -- return 0; -- return sc(kw->key+kwl, label+kwl); -- } -- return 0; -+ int kwl = strlen(kw->key); -+ int ll = strlen(label); -+ int rc; -+ int (*snc)(const char *s1, const char *s2, size_t n) = -+ case_insensitive ? strncasecmp : strncmp; -+ int (*sc)(const char *s1, const char *s2) = -+ case_insensitive ? strcasecmp : strcmp; -+ -+ if (kwl > ll) -+ return ll - kwl; -+ -+ rc = snc(kw->key, label, kwl); -+ if (rc) -+ return rc; -+ -+ if (!label[kwl]) -+ return 0; -+ if (isspace(label[kwl])) -+ return 0; -+ if (kw->separatorChar && label[kwl] == kw->separatorChar) -+ return 0; -+ if (kw->nextChar && label[kwl] == kw->nextChar) -+ return 0; -+ return sc(kw->key+kwl, label+kwl); - } - - static enum lineType_e preferredLineType(enum lineType_e type, -@@ -1034,6 +1036,123 @@ static int lineWrite(FILE * out, struct singleLine *line, - return 0; - } - -+static int mergeElements(struct singleLine *line, int left, int right) -+{ -+ struct lineElement *elements = alloca(sizeof (line->elements[0]) * -+ line->numElements); -+ int i, j; -+ size_t itemsize = 0; -+ size_t newNumElements = 0; -+ char *newitem; -+ char *newindent = NULL; -+ -+ if (right >= line->numElements) -+ right = line->numElements - 1; -+ -+ if (!elements) -+ return -1; -+ for (i = 0; i < left; i++) { -+ elements[i] = line->elements[i]; -+ newNumElements++; -+ } -+ for (; i <= right; i++) { -+ itemsize += strlen(line->elements[i].item); -+ if (line->elements[i].indent && line->elements[i].indent[0]) { -+ if (i != right) -+ itemsize += strlen(line->elements[i].indent); -+ } -+ } -+ newitem = calloc (itemsize+1, 1); -+ if (!newitem) -+ return -1; -+ for (i = left; i <= right; i++) { -+ strcat(newitem, line->elements[i].item); -+ if (line->elements[i].indent) { -+ if (i != right) { -+ strcat(newitem, line->elements[i].indent); -+ free(line->elements[i].indent); -+ } else { -+ newindent = line->elements[i].indent; -+ } -+ } else { -+ newindent = strdup(""); -+ } -+ } -+ newNumElements++; -+ elements[left].item = newitem; -+ elements[left].indent = newindent; -+ if (left+1 < line->numElements && right+1 < line->numElements) { -+ for (j = left+1, i = right+1; i < line->numElements; i++) { -+ elements[j++] = line->elements[i]; -+ newNumElements++; -+ } -+ } -+ memcpy(line->elements, elements, -+ sizeof (line->elements[i]) * newNumElements); -+ line->numElements = newNumElements; -+ return 0; -+} -+ -+static int emptyElement(struct lineElement *element) -+{ -+ if (element->item && strlen(element->item) > 0) -+ return 0; -+ if (element->indent && strlen(element->indent) > 0) -+ return 0; -+ return 1; -+} -+ -+static int splitElement(struct singleLine *line, int element, int splitchar) -+{ -+ struct lineElement split[2] = {{0,0},{0,0}}; -+ struct lineElement *elements = NULL; -+ int saved_errno; -+ int i, j; -+ -+ elements = calloc(line->numElements + 1, sizeof (line->elements[0])); -+ if (!elements) -+ return -1; -+ -+ split[0].item = strndup(line->elements[element].item, splitchar); -+ if (!split[0].item) -+ goto err; -+ split[0].indent = strndup(&line->elements[element].item[splitchar], 1); -+ if (!split[0].indent) -+ goto err; -+ split[1].item = strdup(&line->elements[element].item[splitchar+1]); -+ if (!split[1].item) -+ goto err; -+ split[1].indent = line->elements[element].indent; -+ -+ for (i = j = 0; i < line->numElements; i++) { -+ if (i != element) { -+ memcpy(&elements[j++], &line->elements[i], -+ sizeof(line->elements[i])); -+ } else { -+ memcpy(&elements[j++], &split[0], sizeof(split[0])); -+ memcpy(&elements[j++], &split[1], sizeof(split[1])); -+ free(line->elements[i].item); -+ } -+ } -+ free(line->elements); -+ line->elements = elements; -+ line->numElements++; -+ -+ return 0; -+err: -+ saved_errno = errno; -+ if (split[0].item) -+ free(split[0].item); -+ if (split[0].indent) -+ free(split[0].indent); -+ if (split[1].item) -+ free(split[1].item); -+ if (elements) -+ free(elements); -+ errno = saved_errno; -+ return -1; -+} -+ - /* we've guaranteed that the buffer ends w/ \n\0 */ - static int getNextLine(char **bufPtr, struct singleLine *line, - struct configFileInfo *cfi) -@@ -1208,34 +1327,27 @@ static int getNextLine(char **bufPtr, struct singleLine *line, - * yet a third way to avoid rhbz# XXX FIXME :/ - */ - char *eq; -- int l; -- int numElements = line->numElements; -- struct lineElement *newElements; -+ int rc; -+ rc = mergeElements(line, 2, line->numElements); -+ if (rc < 0) -+ return rc; - eq = strchr(line->elements[1].item, '='); - if (!eq) - return 0; -- l = eq - line->elements[1].item; -- if (eq[1] != 0) -- numElements++; -- newElements = calloc(numElements,sizeof (*newElements)); -- memcpy(&newElements[0], &line->elements[0], -- sizeof (newElements[0])); -- newElements[1].item = -- strndup(line->elements[1].item, l); -- newElements[1].indent = "="; -- *(eq++) = '\0'; -- newElements[2].item = strdup(eq); -- free(line->elements[1].item); -- if (line->elements[1].indent) -- newElements[2].indent = line->elements[1].indent; -- for (int i = 2; i < line->numElements; i++) { -- newElements[i+1].item = line->elements[i].item; -- newElements[i+1].indent = -- line->elements[i].indent; -+ rc = splitElement(line, 1, eq-line->elements[1].item); -+ if (rc < 0) -+ return rc; -+ /* now make sure we haven't got any bogus elements at -+ * the end that don't mean anything. -+ */ -+ while (line->numElements > 1 && -+ emptyElement( -+ &line->elements[line->numElements-1])) { -+ rc = mergeElements(line, line->numElements-2, -+ line->numElements-1); -+ if (rc < 0) -+ return rc; - } -- free(line->elements); -- line->elements = newElements; -- line->numElements = numElements; - } - } - -diff --git a/test.sh b/test.sh -index ba466a5..d488333 100755 ---- a/test.sh -+++ b/test.sh -@@ -551,6 +551,12 @@ if [ "$testgrub2" == "y" ]; then - --copy-default --title 'Red Hat Enterprise Linux Server' \ - --args=root=/dev/mapper/foo-- - -+ # the same, but for: set foo = " bar=1,2 " -+ grub2Test grub2.17 add/g2-1.17 \ -+ --boot-filesystem=/boot --add-kernel=/boot/vmlinuz-foo \ -+ --copy-default --title 'Red Hat Enterprise Linux Server' \ -+ --args=root=/dev/mapper/foo-- -+ - testing="GRUB2 add initrd" - grub2Test grub2.2 add/g2-1.4 --update-kernel=/boot/new-kernel.img \ - --initrd=/boot/new-initrd --boot-filesystem=/boot/ -diff --git a/test/grub2.17 b/test/grub2.17 -new file mode 100644 -index 0000000..bd8c9c5 ---- /dev/null -+++ b/test/grub2.17 -@@ -0,0 +1,156 @@ -+# -+# DO NOT EDIT THIS FILE -+# -+# It is automatically generated by grub2-mkconfig using templates -+# from /etc/grub.d and settings from /etc/default/grub -+# -+ -+### BEGIN /etc/grub.d/00_header ### -+set pager=1 -+ -+if [ -s $prefix/grubenv ]; then -+ load_env -+fi -+if [ "${next_entry}" ] ; then -+ set default="${next_entry}" -+ set next_entry= -+ save_env next_entry -+ set boot_once=true -+else -+ set default="${saved_entry}" -+fi -+ -+if [ x"${feature_menuentry_id}" = xy ]; then -+ menuentry_id_option="--id" -+else -+ menuentry_id_option="" -+fi -+ -+export menuentry_id_option -+ -+if [ "${prev_saved_entry}" ]; then -+ set saved_entry="${prev_saved_entry}" -+ save_env saved_entry -+ set prev_saved_entry= -+ save_env prev_saved_entry -+ set boot_once=true -+fi -+ -+function savedefault { -+ if [ -z "${boot_once}" ]; then -+ saved_entry="${chosen}" -+ save_env saved_entry -+ fi -+} -+ -+function load_video { -+ if [ x$feature_all_video_module = xy ]; then -+ insmod all_video -+ else -+ insmod efi_gop -+ insmod efi_uga -+ insmod ieee1275_fb -+ insmod vbe -+ insmod vga -+ insmod video_bochs -+ insmod video_cirrus -+ fi -+} -+ -+serial --speed=115200 -+terminal_input serial console -+terminal_output serial console -+if [ x$feature_timeout_style = xy ] ; then -+ set timeout_style=menu -+ set timeout=5 -+# Fallback normal timeout code in case the timeout_style feature is -+# unavailable. -+else -+ set timeout=5 -+fi -+### END /etc/grub.d/00_header ### -+ -+### BEGIN /etc/grub.d/00_tuned ### -+set tuned_params= " isolcpus=1,3 " -+### END /etc/grub.d/00_tuned ### -+ -+### BEGIN /etc/grub.d/01_users ### -+if [ -f ${prefix}/user.cfg ]; then -+ source ${prefix}/user.cfg -+ if [ -n ${GRUB2_PASSWORD} ]; then -+ set superusers="root" -+ export superusers -+ password_pbkdf2 root ${GRUB2_PASSWORD} -+ fi -+fi -+### END /etc/grub.d/01_users ### -+ -+### BEGIN /etc/grub.d/10_linux ### -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 -+} -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-3.10.0-296.el7.x86_64.img -+} -+menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img -+} -+if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; -+### END /etc/grub.d/10_linux ### -+ -+### BEGIN /etc/grub.d/20_linux_xen ### -+### END /etc/grub.d/20_linux_xen ### -+ -+### BEGIN /etc/grub.d/20_ppc_terminfo ### -+### END /etc/grub.d/20_ppc_terminfo ### -+ -+### BEGIN /etc/grub.d/30_os-prober ### -+### END /etc/grub.d/30_os-prober ### -+ -+### BEGIN /etc/grub.d/40_custom ### -+# This file provides an easy way to add custom menu entries. Simply type the -+# menu entries you want to add after this comment. Be careful not to change -+# the 'exec tail' line above. -+### END /etc/grub.d/40_custom ### -+ -+### BEGIN /etc/grub.d/41_custom ### -+if [ -f ${config_directory}/custom.cfg ]; then -+ source ${config_directory}/custom.cfg -+elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then -+ source $prefix/custom.cfg; -+fi -+### END /etc/grub.d/41_custom ### -diff --git a/test/results/add/g2-1.17 b/test/results/add/g2-1.17 -new file mode 100644 -index 0000000..afb151d ---- /dev/null -+++ b/test/results/add/g2-1.17 -@@ -0,0 +1,170 @@ -+# -+# DO NOT EDIT THIS FILE -+# -+# It is automatically generated by grub2-mkconfig using templates -+# from /etc/grub.d and settings from /etc/default/grub -+# -+ -+### BEGIN /etc/grub.d/00_header ### -+set pager=1 -+ -+if [ -s $prefix/grubenv ]; then -+ load_env -+fi -+if [ "${next_entry}" ] ; then -+ set default="${next_entry}" -+ set next_entry= -+ save_env next_entry -+ set boot_once=true -+else -+ set default="${saved_entry}" -+fi -+ -+if [ x"${feature_menuentry_id}" = xy ]; then -+ menuentry_id_option="--id" -+else -+ menuentry_id_option="" -+fi -+ -+export menuentry_id_option -+ -+if [ "${prev_saved_entry}" ]; then -+ set saved_entry="${prev_saved_entry}" -+ save_env saved_entry -+ set prev_saved_entry= -+ save_env prev_saved_entry -+ set boot_once=true -+fi -+ -+function savedefault { -+ if [ -z "${boot_once}" ]; then -+ saved_entry="${chosen}" -+ save_env saved_entry -+ fi -+} -+ -+function load_video { -+ if [ x$feature_all_video_module = xy ]; then -+ insmod all_video -+ else -+ insmod efi_gop -+ insmod efi_uga -+ insmod ieee1275_fb -+ insmod vbe -+ insmod vga -+ insmod video_bochs -+ insmod video_cirrus -+ fi -+} -+ -+serial --speed=115200 -+terminal_input serial console -+terminal_output serial console -+if [ x$feature_timeout_style = xy ] ; then -+ set timeout_style=menu -+ set timeout=5 -+# Fallback normal timeout code in case the timeout_style feature is -+# unavailable. -+else -+ set timeout=5 -+fi -+### END /etc/grub.d/00_header ### -+ -+### BEGIN /etc/grub.d/00_tuned ### -+set tuned_params= " isolcpus=1,3 " -+### END /etc/grub.d/00_tuned ### -+ -+### BEGIN /etc/grub.d/01_users ### -+if [ -f ${prefix}/user.cfg ]; then -+ source ${prefix}/user.cfg -+ if [ -n ${GRUB2_PASSWORD} ]; then -+ set superusers="root" -+ export superusers -+ password_pbkdf2 root ${GRUB2_PASSWORD} -+ fi -+fi -+### END /etc/grub.d/01_users ### -+ -+### BEGIN /etc/grub.d/10_linux ### -+menuentry 'Red Hat Enterprise Linux Server' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-foo root=/dev/mapper/foo-- ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 -+} -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 -+} -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-3.10.0-296.el7.x86_64.img -+} -+menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img -+} -+if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; -+### END /etc/grub.d/10_linux ### -+ -+### BEGIN /etc/grub.d/20_linux_xen ### -+### END /etc/grub.d/20_linux_xen ### -+ -+### BEGIN /etc/grub.d/20_ppc_terminfo ### -+### END /etc/grub.d/20_ppc_terminfo ### -+ -+### BEGIN /etc/grub.d/30_os-prober ### -+### END /etc/grub.d/30_os-prober ### -+ -+### BEGIN /etc/grub.d/40_custom ### -+# This file provides an easy way to add custom menu entries. Simply type the -+# menu entries you want to add after this comment. Be careful not to change -+# the 'exec tail' line above. -+### END /etc/grub.d/40_custom ### -+ -+### BEGIN /etc/grub.d/41_custom ### -+if [ -f ${config_directory}/custom.cfg ]; then -+ source ${config_directory}/custom.cfg -+elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then -+ source $prefix/custom.cfg; -+fi -+### END /etc/grub.d/41_custom ### --- -2.4.3 - diff --git a/SOURCES/0001-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch b/SOURCES/0001-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch deleted file mode 100644 index 8ccf23b..0000000 --- a/SOURCES/0001-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 956c9b804607d1a43183514e8a18d671ab14d2fa Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 6 Aug 2015 10:06:13 -0400 -Subject: [PATCH 1/3] Make it possible to run "test.sh --verbose" from the make - command line. - -Signed-off-by: Peter Jones ---- - Makefile | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/Makefile b/Makefile -index 94cef27..e021f35 100644 ---- a/Makefile -+++ b/Makefile -@@ -26,6 +26,10 @@ CC = gcc - RPM_OPT_FLAGS ?= -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector - CFLAGS += $(RPM_OPT_FLAGS) -std=gnu99 -Wall -Werror -Wno-error=unused-function -Wno-unused-function -ggdb - LDFLAGS := -+VERBOSE_TEST := -+ifneq ($(VERBOSE_TEST),) -+ VERBOSE_TEST="--verbose" -+endif - - grubby_LIBS = -lblkid -lpopt - -@@ -39,7 +43,7 @@ debug : clean - - test: all - @export TOPDIR=$(TOPDIR) -- @./test.sh -+ @./test.sh $(VERBOSE_TEST) - - install: all - mkdir -p $(DESTDIR)$(PREFIX)/sbin --- -2.4.3 - diff --git a/SOURCES/0001-Specify-bootloader-directory-in-the-test-case-for-11.patch b/SOURCES/0001-Specify-bootloader-directory-in-the-test-case-for-11.patch deleted file mode 100644 index 79639f8..0000000 --- a/SOURCES/0001-Specify-bootloader-directory-in-the-test-case-for-11.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 2793c9305a1092c03d04a5fe0fa3a56811039447 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 1 Sep 2015 11:02:07 -0400 -Subject: [PATCH] Specify bootloader directory in the test case for 1152550. - -Because otherwise it blows up when built in mock without /boot mounted. - -Related: rhbz#1152550 - -Signed-off-by: Peter Jones ---- - test.sh | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/test.sh b/test.sh -index cd2d870..ba466a5 100755 ---- a/test.sh -+++ b/test.sh -@@ -547,7 +547,7 @@ if [ "$testgrub2" == "y" ]; then - # has this being emitted as: set foo="bar=1,2"=1,2" - # which is wrong. - grub2Test grub2.16 add/g2-1.16 \ -- --add-kernel=/boot/vmlinuz-foo \ -+ --boot-filesystem=/boot --add-kernel=/boot/vmlinuz-foo \ - --copy-default --title 'Red Hat Enterprise Linux Server' \ - --args=root=/dev/mapper/foo-- - --- -2.4.3 - diff --git a/SOURCES/0001-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch b/SOURCES/0001-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch deleted file mode 100644 index f4971af..0000000 --- a/SOURCES/0001-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 8f0ef3e08aaef134ec4acfe87a6628b3fda2243c Mon Sep 17 00:00:00 2001 -From: Don Zickus -Date: Wed, 22 Jul 2015 13:58:53 -0400 -Subject: [PATCH] ppc64le sync grub.cfg changes to disk (#1212114) - -After installing a new kernel, if a panic is induced, not all the kernel -pieces are on the disk (most importantly the grub.cfg changes). This can -lead to a hung system on a reboot because the older kernel can not be found. - -Address this by forcing all the changes (mainly the fs meta data) to disk -before finishing the kernel package installation. - -Tested by 'yum install kernel-...; echo c > /proc/sysrq-trigger'. - -Before, the machine would panic and on reboot be stuck without a grub.cfg -to read. After, works as expected. - -Related: rhbz#1212114 ---- - new-kernel-pkg | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/new-kernel-pkg b/new-kernel-pkg -index 1f6ab39..90652da 100755 ---- a/new-kernel-pkg -+++ b/new-kernel-pkg -@@ -927,4 +927,12 @@ fi - # if we mounted the U-Boot directory, unmount it. - [ -n "$mounted" ] && umount $ubootDir - -+# make sure changes make it to the disk. -+# if /boot is a mountpoint, force the meta data on disk -+# to by-pass writeback delay. -+# PPC64LE-only to deal with Petitboot issues -+if [ "$ARCH" = "ppc64le" ]; then -+ sync && mountpoint -q /boot &&fsfreeze -f /boot && fsfreeze -u /boot -+fi -+ - exit 0 --- -1.8.3.1 - diff --git a/SOURCES/0002-Better-formatting.patch b/SOURCES/0002-Better-formatting.patch deleted file mode 100644 index fafdd95..0000000 --- a/SOURCES/0002-Better-formatting.patch +++ /dev/null @@ -1,9034 +0,0 @@ -From aaea1dbe7731a481a1f62b312a5dd5ac77c10926 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 10 Sep 2015 18:27:31 -0400 -Subject: [PATCH] Reformat to make this easier to work on. - -Signed-off-by: Peter Jones ---- - grubby.c | 8385 +++++++++++++++++++++++++++++++++----------------------------- - 1 file changed, 4406 insertions(+), 3979 deletions(-) - -diff --git a/grubby.c b/grubby.c -index f1af54d..8295a53 100644 ---- a/grubby.c -+++ b/grubby.c -@@ -48,7 +48,7 @@ - #define dbgPrintf(format, args...) - #endif - --int debug = 0; /* Currently just for template debugging */ -+int debug = 0; /* Currently just for template debugging */ - - #define _(A) (A) - -@@ -70,50 +70,50 @@ char *saved_command_line = NULL; - - /* comments get lumped in with indention */ - struct lineElement { -- char * item; -- char * indent; -+ char *item; -+ char *indent; - }; - --enum lineType_e { -- LT_WHITESPACE = 1 << 0, -- LT_TITLE = 1 << 1, -- LT_KERNEL = 1 << 2, -- LT_INITRD = 1 << 3, -- LT_HYPER = 1 << 4, -- LT_DEFAULT = 1 << 5, -- LT_MBMODULE = 1 << 6, -- LT_ROOT = 1 << 7, -- LT_FALLBACK = 1 << 8, -- LT_KERNELARGS = 1 << 9, -- LT_BOOT = 1 << 10, -- LT_BOOTROOT = 1 << 11, -- LT_LBA = 1 << 12, -- LT_OTHER = 1 << 13, -- LT_GENERIC = 1 << 14, -- LT_ECHO = 1 << 16, -- LT_MENUENTRY = 1 << 17, -- LT_ENTRY_END = 1 << 18, -- LT_SET_VARIABLE = 1 << 19, -- LT_KERNEL_EFI = 1 << 20, -- LT_INITRD_EFI = 1 << 21, -- LT_KERNEL_16 = 1 << 22, -- LT_INITRD_16 = 1 << 23, -- LT_UNKNOWN = 1 << 24, -+enum lineType_e { -+ LT_WHITESPACE = 1 << 0, -+ LT_TITLE = 1 << 1, -+ LT_KERNEL = 1 << 2, -+ LT_INITRD = 1 << 3, -+ LT_HYPER = 1 << 4, -+ LT_DEFAULT = 1 << 5, -+ LT_MBMODULE = 1 << 6, -+ LT_ROOT = 1 << 7, -+ LT_FALLBACK = 1 << 8, -+ LT_KERNELARGS = 1 << 9, -+ LT_BOOT = 1 << 10, -+ LT_BOOTROOT = 1 << 11, -+ LT_LBA = 1 << 12, -+ LT_OTHER = 1 << 13, -+ LT_GENERIC = 1 << 14, -+ LT_ECHO = 1 << 16, -+ LT_MENUENTRY = 1 << 17, -+ LT_ENTRY_END = 1 << 18, -+ LT_SET_VARIABLE = 1 << 19, -+ LT_KERNEL_EFI = 1 << 20, -+ LT_INITRD_EFI = 1 << 21, -+ LT_KERNEL_16 = 1 << 22, -+ LT_INITRD_16 = 1 << 23, -+ LT_UNKNOWN = 1 << 24, - }; - - struct singleLine { -- char * indent; -- int numElements; -- struct lineElement * elements; -- struct singleLine * next; -- enum lineType_e type; -+ char *indent; -+ int numElements; -+ struct lineElement *elements; -+ struct singleLine *next; -+ enum lineType_e type; - }; - - struct singleEntry { -- struct singleLine * lines; -- int skip; -- int multiboot; -- struct singleEntry * next; -+ struct singleLine *lines; -+ int skip; -+ int multiboot; -+ struct singleEntry *next; - }; - - #define GRUBBY_BADIMAGE_OKAY (1 << 0) -@@ -133,1718 +133,1837 @@ struct singleEntry { - #define DEFAULT_SAVED_GRUB2 -3 - - struct keywordTypes { -- char * key; -- enum lineType_e type; -- char nextChar; -- char separatorChar; -+ char *key; -+ enum lineType_e type; -+ char nextChar; -+ char separatorChar; - }; - - struct configFileInfo; - --typedef const char *(*findConfigFunc)(struct configFileInfo *); --typedef const int (*writeLineFunc)(struct configFileInfo *, -- struct singleLine *line); --typedef char *(*getEnvFunc)(struct configFileInfo *, char *name); --typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value); -+typedef const char *(*findConfigFunc) (struct configFileInfo *); -+typedef const int (*writeLineFunc) (struct configFileInfo *, -+ struct singleLine * line); -+typedef char *(*getEnvFunc) (struct configFileInfo *, char *name); -+typedef int (*setEnvFunc) (struct configFileInfo *, char *name, char *value); - - struct configFileInfo { -- char * defaultConfig; -- findConfigFunc findConfig; -- writeLineFunc writeLine; -- getEnvFunc getEnv; -- setEnvFunc setEnv; -- struct keywordTypes * keywords; -- int caseInsensitive; -- int defaultIsIndex; -- int defaultIsVariable; -- int defaultSupportSaved; -- int defaultIsSaved; -- int defaultIsUnquoted; -- enum lineType_e entryStart; -- enum lineType_e entryEnd; -- int needsBootPrefix; -- int argsInQuotes; -- int maxTitleLength; -- int titleBracketed; -- int titlePosition; -- int mbHyperFirst; -- int mbInitRdIsModule; -- int mbConcatArgs; -- int mbAllowExtraInitRds; -- char *envFile; -+ char *defaultConfig; -+ findConfigFunc findConfig; -+ writeLineFunc writeLine; -+ getEnvFunc getEnv; -+ setEnvFunc setEnv; -+ struct keywordTypes *keywords; -+ int caseInsensitive; -+ int defaultIsIndex; -+ int defaultIsVariable; -+ int defaultSupportSaved; -+ int defaultIsSaved; -+ int defaultIsUnquoted; -+ enum lineType_e entryStart; -+ enum lineType_e entryEnd; -+ int needsBootPrefix; -+ int argsInQuotes; -+ int maxTitleLength; -+ int titleBracketed; -+ int titlePosition; -+ int mbHyperFirst; -+ int mbInitRdIsModule; -+ int mbConcatArgs; -+ int mbAllowExtraInitRds; -+ char *envFile; - }; - - struct keywordTypes grubKeywords[] = { -- { "title", LT_TITLE, ' ' }, -- { "root", LT_BOOTROOT, ' ' }, -- { "default", LT_DEFAULT, ' ' }, -- { "fallback", LT_FALLBACK, ' ' }, -- { "kernel", LT_KERNEL, ' ' }, -- { "initrd", LT_INITRD, ' ', ' ' }, -- { "module", LT_MBMODULE, ' ' }, -- { "kernel", LT_HYPER, ' ' }, -- { NULL, 0, 0 }, -+ {"title", LT_TITLE, ' '}, -+ {"root", LT_BOOTROOT, ' '}, -+ {"default", LT_DEFAULT, ' '}, -+ {"fallback", LT_FALLBACK, ' '}, -+ {"kernel", LT_KERNEL, ' '}, -+ {"initrd", LT_INITRD, ' ', ' '}, -+ {"module", LT_MBMODULE, ' '}, -+ {"kernel", LT_HYPER, ' '}, -+ {NULL, 0, 0}, - }; - --const char *grubFindConfig(struct configFileInfo *cfi) { -- static const char *configFiles[] = { -- "/boot/grub/menu.lst", -- "/etc/grub.conf", -- NULL -- }; -- static int i = -1; -- -- if (i == -1) { -- for (i = 0; configFiles[i] != NULL; i++) { -- dbgPrintf("Checking \"%s\": ", configFiles[i]); -- if (!access(configFiles[i], R_OK)) { -- dbgPrintf("found\n"); -- return configFiles[i]; -- } -- dbgPrintf("not found\n"); -+const char *grubFindConfig(struct configFileInfo *cfi) -+{ -+ static const char *configFiles[] = { -+ "/boot/grub/menu.lst", -+ "/etc/grub.conf", -+ NULL -+ }; -+ static int i = -1; -+ -+ if (i == -1) { -+ for (i = 0; configFiles[i] != NULL; i++) { -+ dbgPrintf("Checking \"%s\": ", configFiles[i]); -+ if (!access(configFiles[i], R_OK)) { -+ dbgPrintf("found\n"); -+ return configFiles[i]; -+ } -+ dbgPrintf("not found\n"); -+ } - } -- } -- return configFiles[i]; -+ return configFiles[i]; - } - - struct configFileInfo grubConfigType = { -- .findConfig = grubFindConfig, -- .keywords = grubKeywords, -- .defaultIsIndex = 1, -- .defaultSupportSaved = 1, -- .entryStart = LT_TITLE, -- .needsBootPrefix = 1, -- .mbHyperFirst = 1, -- .mbInitRdIsModule = 1, -- .mbAllowExtraInitRds = 1, -- .titlePosition = 1, -+ .findConfig = grubFindConfig, -+ .keywords = grubKeywords, -+ .defaultIsIndex = 1, -+ .defaultSupportSaved = 1, -+ .entryStart = LT_TITLE, -+ .needsBootPrefix = 1, -+ .mbHyperFirst = 1, -+ .mbInitRdIsModule = 1, -+ .mbAllowExtraInitRds = 1, -+ .titlePosition = 1, - }; - - struct keywordTypes grub2Keywords[] = { -- { "menuentry", LT_MENUENTRY, ' ' }, -- { "}", LT_ENTRY_END, ' ' }, -- { "echo", LT_ECHO, ' ' }, -- { "set", LT_SET_VARIABLE,' ', '=' }, -- { "root", LT_BOOTROOT, ' ' }, -- { "default", LT_DEFAULT, ' ' }, -- { "fallback", LT_FALLBACK, ' ' }, -- { "linux", LT_KERNEL, ' ' }, -- { "linuxefi", LT_KERNEL_EFI, ' ' }, -- { "linux16", LT_KERNEL_16, ' ' }, -- { "initrd", LT_INITRD, ' ', ' ' }, -- { "initrdefi", LT_INITRD_EFI, ' ', ' ' }, -- { "initrd16", LT_INITRD_16, ' ', ' ' }, -- { "module", LT_MBMODULE, ' ' }, -- { "kernel", LT_HYPER, ' ' }, -- { NULL, 0, 0 }, -+ {"menuentry", LT_MENUENTRY, ' '}, -+ {"}", LT_ENTRY_END, ' '}, -+ {"echo", LT_ECHO, ' '}, -+ {"set", LT_SET_VARIABLE, ' ', '='}, -+ {"root", LT_BOOTROOT, ' '}, -+ {"default", LT_DEFAULT, ' '}, -+ {"fallback", LT_FALLBACK, ' '}, -+ {"linux", LT_KERNEL, ' '}, -+ {"linuxefi", LT_KERNEL_EFI, ' '}, -+ {"linux16", LT_KERNEL_16, ' '}, -+ {"initrd", LT_INITRD, ' ', ' '}, -+ {"initrdefi", LT_INITRD_EFI, ' ', ' '}, -+ {"initrd16", LT_INITRD_16, ' ', ' '}, -+ {"module", LT_MBMODULE, ' '}, -+ {"kernel", LT_HYPER, ' '}, -+ {NULL, 0, 0}, - }; - --const char *grub2FindConfig(struct configFileInfo *cfi) { -- static const char *configFiles[] = { -- "/etc/grub2-efi.cfg", -- "/etc/grub2.cfg", -- NULL -- }; -- static int i = -1; -- static const char *grub_cfg = "/boot/grub/grub.cfg"; -- int rc = -1; -- -- if (i == -1) { -- for (i = 0; configFiles[i] != NULL; i++) { -- dbgPrintf("Checking \"%s\": ", configFiles[i]); -- if ((rc = access(configFiles[i], R_OK))) { -- if (errno == EACCES) { -- printf("Unable to access bootloader configuration file " -- "\"%s\": %m\n", configFiles[i]); -- exit(1); -+const char *grub2FindConfig(struct configFileInfo *cfi) -+{ -+ static const char *configFiles[] = { -+ "/etc/grub2-efi.cfg", -+ "/etc/grub2.cfg", -+ NULL -+ }; -+ static int i = -1; -+ static const char *grub_cfg = "/boot/grub/grub.cfg"; -+ int rc = -1; -+ -+ if (i == -1) { -+ for (i = 0; configFiles[i] != NULL; i++) { -+ dbgPrintf("Checking \"%s\": ", configFiles[i]); -+ if ((rc = access(configFiles[i], R_OK))) { -+ if (errno == EACCES) { -+ printf -+ ("Unable to access bootloader configuration file " -+ "\"%s\": %m\n", configFiles[i]); -+ exit(1); -+ } -+ continue; -+ } else { -+ dbgPrintf("found\n"); -+ return configFiles[i]; -+ } - } -- continue; -- } else { -- dbgPrintf("found\n"); -- return configFiles[i]; -- } - } -- } - -- /* Ubuntu renames grub2 to grub, so check for the grub.d directory -- * that isn't in grub1, and if it exists, return the config file path -- * that they use. */ -- if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) { -- dbgPrintf("found\n"); -- return grub_cfg; -- } -+ /* Ubuntu renames grub2 to grub, so check for the grub.d directory -+ * that isn't in grub1, and if it exists, return the config file path -+ * that they use. */ -+ if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) { -+ dbgPrintf("found\n"); -+ return grub_cfg; -+ } - -- dbgPrintf("not found\n"); -- return configFiles[i]; -+ dbgPrintf("not found\n"); -+ return configFiles[i]; - } - - /* kind of hacky. It'll give the first 1024 bytes, ish. */ - static char *grub2GetEnv(struct configFileInfo *info, char *name) - { -- static char buf[1025]; -- char *s = NULL; -- char *ret = NULL; -- char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; -- int rc = asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name); -- -- if (rc < 0) -- return NULL; -- -- FILE *f = popen(s, "r"); -- if (!f) -- goto out; -- -- memset(buf, '\0', sizeof (buf)); -- ret = fgets(buf, 1024, f); -- pclose(f); -- -- if (ret) { -- ret += strlen(name) + 1; -- ret[strlen(ret) - 1] = '\0'; -- } -- dbgPrintf("grub2GetEnv(%s): %s\n", name, ret); -+ static char buf[1025]; -+ char *s = NULL; -+ char *ret = NULL; -+ char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; -+ int rc = -+ asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name); -+ -+ if (rc < 0) -+ return NULL; -+ -+ FILE *f = popen(s, "r"); -+ if (!f) -+ goto out; -+ -+ memset(buf, '\0', sizeof(buf)); -+ ret = fgets(buf, 1024, f); -+ pclose(f); -+ -+ if (ret) { -+ ret += strlen(name) + 1; -+ ret[strlen(ret) - 1] = '\0'; -+ } -+ dbgPrintf("grub2GetEnv(%s): %s\n", name, ret); - out: -- free(s); -- return ret; -+ free(s); -+ return ret; - } - - static int sPopCount(const char *s, const char *c) - { -- int ret = 0; -- if (!s) -- return -1; -- for (int i = 0; s[i] != '\0'; i++) -- for (int j = 0; c[j] != '\0'; j++) -- if (s[i] == c[j]) -- ret++; -- return ret; -+ int ret = 0; -+ if (!s) -+ return -1; -+ for (int i = 0; s[i] != '\0'; i++) -+ for (int j = 0; c[j] != '\0'; j++) -+ if (s[i] == c[j]) -+ ret++; -+ return ret; - } - - static char *shellEscape(const char *s) - { -- int l = strlen(s) + sPopCount(s, "'") * 2; -- -- char *ret = calloc(l+1, sizeof (*ret)); -- if (!ret) -- return NULL; -- for (int i = 0, j = 0; s[i] != '\0'; i++, j++) { -- if (s[i] == '\'') -- ret[j++] = '\\'; -- ret[j] = s[i]; -- } -- return ret; -+ int l = strlen(s) + sPopCount(s, "'") * 2; -+ -+ char *ret = calloc(l + 1, sizeof(*ret)); -+ if (!ret) -+ return NULL; -+ for (int i = 0, j = 0; s[i] != '\0'; i++, j++) { -+ if (s[i] == '\'') -+ ret[j++] = '\\'; -+ ret[j] = s[i]; -+ } -+ return ret; - } - - static void unquote(char *s) - { -- int l = strlen(s); -+ int l = strlen(s); - -- if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) { -- memmove(s, s+1, l-2); -- s[l-2] = '\0'; -- } -+ if ((s[l - 1] == '\'' && s[0] == '\'') -+ || (s[l - 1] == '"' && s[0] == '"')) { -+ memmove(s, s + 1, l - 2); -+ s[l - 2] = '\0'; -+ } - } - - static int grub2SetEnv(struct configFileInfo *info, char *name, char *value) - { -- char *s = NULL; -- int rc = 0; -- char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; -- -- unquote(value); -- value = shellEscape(value); -- if (!value) -- return -1; -- -- rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value); -- free(value); -- if (rc <0) -- return -1; -- -- dbgPrintf("grub2SetEnv(%s): %s\n", name, s); -- rc = system(s); -- free(s); -- return rc; -+ char *s = NULL; -+ int rc = 0; -+ char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; -+ -+ unquote(value); -+ value = shellEscape(value); -+ if (!value) -+ return -1; -+ -+ rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value); -+ free(value); -+ if (rc < 0) -+ return -1; -+ -+ dbgPrintf("grub2SetEnv(%s): %s\n", name, s); -+ rc = system(s); -+ free(s); -+ return rc; - } - - /* this is a gigantic hack to avoid clobbering grub2 variables... */ - static int is_special_grub2_variable(const char *name) - { -- if (!strcmp(name,"\"${next_entry}\"")) -- return 1; -- if (!strcmp(name,"\"${prev_saved_entry}\"")) -- return 1; -- return 0; -+ if (!strcmp(name, "\"${next_entry}\"")) -+ return 1; -+ if (!strcmp(name, "\"${prev_saved_entry}\"")) -+ return 1; -+ return 0; - } - --int sizeOfSingleLine(struct singleLine * line) { -- int count = 0; -+int sizeOfSingleLine(struct singleLine *line) -+{ -+ int count = 0; - -- for (int i = 0; i < line->numElements; i++) { -- int indentSize = 0; -+ for (int i = 0; i < line->numElements; i++) { -+ int indentSize = 0; - -- count = count + strlen(line->elements[i].item); -+ count = count + strlen(line->elements[i].item); - -- indentSize = strlen(line->elements[i].indent); -- if (indentSize > 0) -- count = count + indentSize; -- else -- /* be extra safe and add room for whitespaces */ -- count = count + 1; -- } -+ indentSize = strlen(line->elements[i].indent); -+ if (indentSize > 0) -+ count = count + indentSize; -+ else -+ /* be extra safe and add room for whitespaces */ -+ count = count + 1; -+ } - -- /* room for trailing terminator */ -- count = count + 1; -+ /* room for trailing terminator */ -+ count = count + 1; - -- return count; -+ return count; - } - - static int isquote(char q) - { -- if (q == '\'' || q == '\"') -- return 1; -- return 0; -+ if (q == '\'' || q == '\"') -+ return 1; -+ return 0; - } - --static int iskernel(enum lineType_e type) { -- return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16); -+static int iskernel(enum lineType_e type) -+{ -+ return (type == LT_KERNEL || type == LT_KERNEL_EFI -+ || type == LT_KERNEL_16); - } - --static int isinitrd(enum lineType_e type) { -- return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16); -+static int isinitrd(enum lineType_e type) -+{ -+ return (type == LT_INITRD || type == LT_INITRD_EFI -+ || type == LT_INITRD_16); - } - --char *grub2ExtractTitle(struct singleLine * line) { -- char * current; -- char * current_indent; -- int current_len; -- int current_indent_len; -- int i; -+char *grub2ExtractTitle(struct singleLine *line) -+{ -+ char *current; -+ char *current_indent; -+ int current_len; -+ int current_indent_len; -+ int i; - -- /* bail out if line does not start with menuentry */ -- if (strcmp(line->elements[0].item, "menuentry")) -- return NULL; -+ /* bail out if line does not start with menuentry */ -+ if (strcmp(line->elements[0].item, "menuentry")) -+ return NULL; - -- i = 1; -- current = line->elements[i].item; -- current_len = strlen(current); -- -- /* if second word is quoted, strip the quotes and return single word */ -- if (isquote(*current) && isquote(current[current_len - 1])) { -- char *tmp; -- -- tmp = strdup(current+1); -- if (!tmp) -- return NULL; -- tmp[strlen(tmp)-1] = '\0'; -- return tmp; -- } -- -- /* if no quotes, return second word verbatim */ -- if (!isquote(*current)) -- return current; -- -- /* second element start with a quote, so we have to find the element -- * whose last character is also quote (assuming it's the closing one) */ -- int resultMaxSize; -- char * result; -- /* need to ensure that ' does not match " as we search */ -- char quote_char = *current; -- -- resultMaxSize = sizeOfSingleLine(line); -- result = malloc(resultMaxSize); -- snprintf(result, resultMaxSize, "%s", ++current); -- -- i++; -- for (; i < line->numElements; ++i) { -+ i = 1; - current = line->elements[i].item; - current_len = strlen(current); -- current_indent = line->elements[i].indent; -- current_indent_len = strlen(current_indent); - -- strncat(result, current_indent, current_indent_len); -- if (current[current_len-1] != quote_char) { -- strncat(result, current, current_len); -- } else { -- strncat(result, current, current_len - 1); -- break; -+ /* if second word is quoted, strip the quotes and return single word */ -+ if (isquote(*current) && isquote(current[current_len - 1])) { -+ char *tmp; -+ -+ tmp = strdup(current + 1); -+ if (!tmp) -+ return NULL; -+ tmp[strlen(tmp) - 1] = '\0'; -+ return tmp; -+ } -+ -+ /* if no quotes, return second word verbatim */ -+ if (!isquote(*current)) -+ return current; -+ -+ /* second element start with a quote, so we have to find the element -+ * whose last character is also quote (assuming it's the closing one) */ -+ int resultMaxSize; -+ char *result; -+ /* need to ensure that ' does not match " as we search */ -+ char quote_char = *current; -+ -+ resultMaxSize = sizeOfSingleLine(line); -+ result = malloc(resultMaxSize); -+ snprintf(result, resultMaxSize, "%s", ++current); -+ -+ i++; -+ for (; i < line->numElements; ++i) { -+ current = line->elements[i].item; -+ current_len = strlen(current); -+ current_indent = line->elements[i].indent; -+ current_indent_len = strlen(current_indent); -+ -+ strncat(result, current_indent, current_indent_len); -+ if (current[current_len - 1] != quote_char) { -+ strncat(result, current, current_len); -+ } else { -+ strncat(result, current, current_len - 1); -+ break; -+ } - } -- } -- return result; -+ return result; - } - - struct configFileInfo grub2ConfigType = { -- .findConfig = grub2FindConfig, -- .getEnv = grub2GetEnv, -- .setEnv = grub2SetEnv, -- .keywords = grub2Keywords, -- .defaultIsIndex = 1, -- .defaultSupportSaved = 1, -- .defaultIsVariable = 1, -- .entryStart = LT_MENUENTRY, -- .entryEnd = LT_ENTRY_END, -- .titlePosition = 1, -- .needsBootPrefix = 1, -- .mbHyperFirst = 1, -- .mbInitRdIsModule = 1, -- .mbAllowExtraInitRds = 1, -+ .findConfig = grub2FindConfig, -+ .getEnv = grub2GetEnv, -+ .setEnv = grub2SetEnv, -+ .keywords = grub2Keywords, -+ .defaultIsIndex = 1, -+ .defaultSupportSaved = 1, -+ .defaultIsVariable = 1, -+ .entryStart = LT_MENUENTRY, -+ .entryEnd = LT_ENTRY_END, -+ .titlePosition = 1, -+ .needsBootPrefix = 1, -+ .mbHyperFirst = 1, -+ .mbInitRdIsModule = 1, -+ .mbAllowExtraInitRds = 1, - }; - - struct keywordTypes yabootKeywords[] = { -- { "label", LT_TITLE, '=' }, -- { "root", LT_ROOT, '=' }, -- { "default", LT_DEFAULT, '=' }, -- { "image", LT_KERNEL, '=' }, -- { "bsd", LT_GENERIC, '=' }, -- { "macos", LT_GENERIC, '=' }, -- { "macosx", LT_GENERIC, '=' }, -- { "magicboot", LT_GENERIC, '=' }, -- { "darwin", LT_GENERIC, '=' }, -- { "timeout", LT_GENERIC, '=' }, -- { "install", LT_GENERIC, '=' }, -- { "fstype", LT_GENERIC, '=' }, -- { "hfstype", LT_GENERIC, '=' }, -- { "delay", LT_GENERIC, '=' }, -- { "defaultos", LT_GENERIC, '=' }, -- { "init-message", LT_GENERIC, '=' }, -- { "enablecdboot", LT_GENERIC, ' ' }, -- { "enableofboot", LT_GENERIC, ' ' }, -- { "enablenetboot", LT_GENERIC, ' ' }, -- { "nonvram", LT_GENERIC, ' ' }, -- { "hide", LT_GENERIC, ' ' }, -- { "protect", LT_GENERIC, ' ' }, -- { "nobless", LT_GENERIC, ' ' }, -- { "nonvram", LT_GENERIC, ' ' }, -- { "brokenosx", LT_GENERIC, ' ' }, -- { "usemount", LT_GENERIC, ' ' }, -- { "mntpoint", LT_GENERIC, '=' }, -- { "partition", LT_GENERIC, '=' }, -- { "device", LT_GENERIC, '=' }, -- { "fstype", LT_GENERIC, '=' }, -- { "initrd", LT_INITRD, '=', ';' }, -- { "append", LT_KERNELARGS, '=' }, -- { "boot", LT_BOOT, '=' }, -- { "lba", LT_LBA, ' ' }, -- { NULL, 0, 0 }, -+ {"label", LT_TITLE, '='}, -+ {"root", LT_ROOT, '='}, -+ {"default", LT_DEFAULT, '='}, -+ {"image", LT_KERNEL, '='}, -+ {"bsd", LT_GENERIC, '='}, -+ {"macos", LT_GENERIC, '='}, -+ {"macosx", LT_GENERIC, '='}, -+ {"magicboot", LT_GENERIC, '='}, -+ {"darwin", LT_GENERIC, '='}, -+ {"timeout", LT_GENERIC, '='}, -+ {"install", LT_GENERIC, '='}, -+ {"fstype", LT_GENERIC, '='}, -+ {"hfstype", LT_GENERIC, '='}, -+ {"delay", LT_GENERIC, '='}, -+ {"defaultos", LT_GENERIC, '='}, -+ {"init-message", LT_GENERIC, '='}, -+ {"enablecdboot", LT_GENERIC, ' '}, -+ {"enableofboot", LT_GENERIC, ' '}, -+ {"enablenetboot", LT_GENERIC, ' '}, -+ {"nonvram", LT_GENERIC, ' '}, -+ {"hide", LT_GENERIC, ' '}, -+ {"protect", LT_GENERIC, ' '}, -+ {"nobless", LT_GENERIC, ' '}, -+ {"nonvram", LT_GENERIC, ' '}, -+ {"brokenosx", LT_GENERIC, ' '}, -+ {"usemount", LT_GENERIC, ' '}, -+ {"mntpoint", LT_GENERIC, '='}, -+ {"partition", LT_GENERIC, '='}, -+ {"device", LT_GENERIC, '='}, -+ {"fstype", LT_GENERIC, '='}, -+ {"initrd", LT_INITRD, '=', ';'}, -+ {"append", LT_KERNELARGS, '='}, -+ {"boot", LT_BOOT, '='}, -+ {"lba", LT_LBA, ' '}, -+ {NULL, 0, 0}, - }; - - struct keywordTypes liloKeywords[] = { -- { "label", LT_TITLE, '=' }, -- { "root", LT_ROOT, '=' }, -- { "default", LT_DEFAULT, '=' }, -- { "image", LT_KERNEL, '=' }, -- { "other", LT_OTHER, '=' }, -- { "initrd", LT_INITRD, '=' }, -- { "append", LT_KERNELARGS, '=' }, -- { "boot", LT_BOOT, '=' }, -- { "lba", LT_LBA, ' ' }, -- { NULL, 0, 0 }, -+ {"label", LT_TITLE, '='}, -+ {"root", LT_ROOT, '='}, -+ {"default", LT_DEFAULT, '='}, -+ {"image", LT_KERNEL, '='}, -+ {"other", LT_OTHER, '='}, -+ {"initrd", LT_INITRD, '='}, -+ {"append", LT_KERNELARGS, '='}, -+ {"boot", LT_BOOT, '='}, -+ {"lba", LT_LBA, ' '}, -+ {NULL, 0, 0}, - }; - - struct keywordTypes eliloKeywords[] = { -- { "label", LT_TITLE, '=' }, -- { "root", LT_ROOT, '=' }, -- { "default", LT_DEFAULT, '=' }, -- { "image", LT_KERNEL, '=' }, -- { "initrd", LT_INITRD, '=' }, -- { "append", LT_KERNELARGS, '=' }, -- { "vmm", LT_HYPER, '=' }, -- { NULL, 0, 0 }, -+ {"label", LT_TITLE, '='}, -+ {"root", LT_ROOT, '='}, -+ {"default", LT_DEFAULT, '='}, -+ {"image", LT_KERNEL, '='}, -+ {"initrd", LT_INITRD, '='}, -+ {"append", LT_KERNELARGS, '='}, -+ {"vmm", LT_HYPER, '='}, -+ {NULL, 0, 0}, - }; - - struct keywordTypes siloKeywords[] = { -- { "label", LT_TITLE, '=' }, -- { "root", LT_ROOT, '=' }, -- { "default", LT_DEFAULT, '=' }, -- { "image", LT_KERNEL, '=' }, -- { "other", LT_OTHER, '=' }, -- { "initrd", LT_INITRD, '=' }, -- { "append", LT_KERNELARGS, '=' }, -- { "boot", LT_BOOT, '=' }, -- { NULL, 0, 0 }, -+ {"label", LT_TITLE, '='}, -+ {"root", LT_ROOT, '='}, -+ {"default", LT_DEFAULT, '='}, -+ {"image", LT_KERNEL, '='}, -+ {"other", LT_OTHER, '='}, -+ {"initrd", LT_INITRD, '='}, -+ {"append", LT_KERNELARGS, '='}, -+ {"boot", LT_BOOT, '='}, -+ {NULL, 0, 0}, - }; - - struct keywordTypes ziplKeywords[] = { -- { "target", LT_BOOTROOT, '=' }, -- { "image", LT_KERNEL, '=' }, -- { "ramdisk", LT_INITRD, '=' }, -- { "parameters", LT_KERNELARGS, '=' }, -- { "default", LT_DEFAULT, '=' }, -- { NULL, 0, 0 }, -+ {"target", LT_BOOTROOT, '='}, -+ {"image", LT_KERNEL, '='}, -+ {"ramdisk", LT_INITRD, '='}, -+ {"parameters", LT_KERNELARGS, '='}, -+ {"default", LT_DEFAULT, '='}, -+ {NULL, 0, 0}, - }; - - struct keywordTypes extlinuxKeywords[] = { -- { "label", LT_TITLE, ' ' }, -- { "root", LT_ROOT, ' ' }, -- { "default", LT_DEFAULT, ' ' }, -- { "kernel", LT_KERNEL, ' ' }, -- { "initrd", LT_INITRD, ' ', ',' }, -- { "append", LT_KERNELARGS, ' ' }, -- { "prompt", LT_UNKNOWN, ' ' }, -- { NULL, 0, 0 }, -+ {"label", LT_TITLE, ' '}, -+ {"root", LT_ROOT, ' '}, -+ {"default", LT_DEFAULT, ' '}, -+ {"kernel", LT_KERNEL, ' '}, -+ {"initrd", LT_INITRD, ' ', ','}, -+ {"append", LT_KERNELARGS, ' '}, -+ {"prompt", LT_UNKNOWN, ' '}, -+ {NULL, 0, 0}, - }; -+ - int useextlinuxmenu; - struct configFileInfo eliloConfigType = { -- .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf", -- .keywords = eliloKeywords, -- .entryStart = LT_KERNEL, -- .needsBootPrefix = 1, -- .argsInQuotes = 1, -- .mbConcatArgs = 1, -- .titlePosition = 1, -+ .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf", -+ .keywords = eliloKeywords, -+ .entryStart = LT_KERNEL, -+ .needsBootPrefix = 1, -+ .argsInQuotes = 1, -+ .mbConcatArgs = 1, -+ .titlePosition = 1, - }; - - struct configFileInfo liloConfigType = { -- .defaultConfig = "/etc/lilo.conf", -- .keywords = liloKeywords, -- .entryStart = LT_KERNEL, -- .argsInQuotes = 1, -- .maxTitleLength = 15, -- .titlePosition = 1, -+ .defaultConfig = "/etc/lilo.conf", -+ .keywords = liloKeywords, -+ .entryStart = LT_KERNEL, -+ .argsInQuotes = 1, -+ .maxTitleLength = 15, -+ .titlePosition = 1, - }; - - struct configFileInfo yabootConfigType = { -- .defaultConfig = "/etc/yaboot.conf", -- .keywords = yabootKeywords, -- .entryStart = LT_KERNEL, -- .needsBootPrefix = 1, -- .argsInQuotes = 1, -- .maxTitleLength = 15, -- .mbAllowExtraInitRds = 1, -- .titlePosition = 1, -+ .defaultConfig = "/etc/yaboot.conf", -+ .keywords = yabootKeywords, -+ .entryStart = LT_KERNEL, -+ .needsBootPrefix = 1, -+ .argsInQuotes = 1, -+ .maxTitleLength = 15, -+ .mbAllowExtraInitRds = 1, -+ .titlePosition = 1, - }; - - struct configFileInfo siloConfigType = { -- .defaultConfig = "/etc/silo.conf", -- .keywords = siloKeywords, -- .entryStart = LT_KERNEL, -- .needsBootPrefix = 1, -- .argsInQuotes = 1, -- .maxTitleLength = 15, -- .titlePosition = 1, -+ .defaultConfig = "/etc/silo.conf", -+ .keywords = siloKeywords, -+ .entryStart = LT_KERNEL, -+ .needsBootPrefix = 1, -+ .argsInQuotes = 1, -+ .maxTitleLength = 15, -+ .titlePosition = 1, - }; - - struct configFileInfo ziplConfigType = { -- .defaultConfig = "/etc/zipl.conf", -- .keywords = ziplKeywords, -- .entryStart = LT_TITLE, -- .argsInQuotes = 1, -- .titleBracketed = 1, -+ .defaultConfig = "/etc/zipl.conf", -+ .keywords = ziplKeywords, -+ .entryStart = LT_TITLE, -+ .argsInQuotes = 1, -+ .titleBracketed = 1, - }; - - struct configFileInfo extlinuxConfigType = { -- .defaultConfig = "/boot/extlinux/extlinux.conf", -- .keywords = extlinuxKeywords, -- .caseInsensitive = 1, -- .entryStart = LT_TITLE, -- .needsBootPrefix = 1, -- .maxTitleLength = 255, -- .mbAllowExtraInitRds = 1, -- .defaultIsUnquoted = 1, -- .titlePosition = 1, -+ .defaultConfig = "/boot/extlinux/extlinux.conf", -+ .keywords = extlinuxKeywords, -+ .caseInsensitive = 1, -+ .entryStart = LT_TITLE, -+ .needsBootPrefix = 1, -+ .maxTitleLength = 255, -+ .mbAllowExtraInitRds = 1, -+ .defaultIsUnquoted = 1, -+ .titlePosition = 1, - }; - - struct grubConfig { -- struct singleLine * theLines; -- struct singleEntry * entries; -- char * primaryIndent; -- char * secondaryIndent; -- int defaultImage; /* -1 if none specified -- this value is -- * written out, overriding original */ -- int fallbackImage; /* just like defaultImage */ -- int flags; -- struct configFileInfo * cfi; -+ struct singleLine *theLines; -+ struct singleEntry *entries; -+ char *primaryIndent; -+ char *secondaryIndent; -+ int defaultImage; /* -1 if none specified -- this value is -+ * written out, overriding original */ -+ int fallbackImage; /* just like defaultImage */ -+ int flags; -+ struct configFileInfo *cfi; - }; - - blkid_cache blkid; - --struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index); --struct singleEntry * findEntryByPath(struct grubConfig * cfg, -- const char * path, const char * prefix, -- int * index); --struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title, -- int * index); --static int readFile(int fd, char ** bufPtr); --static void lineInit(struct singleLine * line); --struct singleLine * lineDup(struct singleLine * line); --static void lineFree(struct singleLine * line); --static int lineWrite(FILE * out, struct singleLine * line, -- struct configFileInfo * cfi); --static int getNextLine(char ** bufPtr, struct singleLine * line, -- struct configFileInfo * cfi); --static char * getRootSpecifier(char * str); --static void requote(struct singleLine *line, struct configFileInfo * cfi); --static void insertElement(struct singleLine * line, -- const char * item, int insertHere, -- struct configFileInfo * cfi); --static void removeElement(struct singleLine * line, int removeHere); --static struct keywordTypes * getKeywordByType(enum lineType_e type, -- struct configFileInfo * cfi); --static enum lineType_e getTypeByKeyword(char * keyword, -- struct configFileInfo * cfi); --static struct singleLine * getLineByType(enum lineType_e type, -- struct singleLine * line); --static int checkForExtLinux(struct grubConfig * config); --struct singleLine * addLineTmpl(struct singleEntry * entry, -- struct singleLine * tmplLine, -- struct singleLine * prevLine, -- const char * val, -- struct configFileInfo * cfi); --struct singleLine * addLine(struct singleEntry * entry, -- struct configFileInfo * cfi, -- enum lineType_e type, char * defaultIndent, -- const char * val); -- --static char * sdupprintf(const char *format, ...) -+struct singleEntry *findEntryByIndex(struct grubConfig *cfg, int index); -+struct singleEntry *findEntryByPath(struct grubConfig *cfg, -+ const char *path, const char *prefix, -+ int *index); -+struct singleEntry *findEntryByTitle(struct grubConfig *cfg, char *title, -+ int *index); -+static int readFile(int fd, char **bufPtr); -+static void lineInit(struct singleLine *line); -+struct singleLine *lineDup(struct singleLine *line); -+static void lineFree(struct singleLine *line); -+static int lineWrite(FILE * out, struct singleLine *line, -+ struct configFileInfo *cfi); -+static int getNextLine(char **bufPtr, struct singleLine *line, -+ struct configFileInfo *cfi); -+static char *getRootSpecifier(char *str); -+static void requote(struct singleLine *line, struct configFileInfo *cfi); -+static void insertElement(struct singleLine *line, -+ const char *item, int insertHere, -+ struct configFileInfo *cfi); -+static void removeElement(struct singleLine *line, int removeHere); -+static struct keywordTypes *getKeywordByType(enum lineType_e type, -+ struct configFileInfo *cfi); -+static enum lineType_e getTypeByKeyword(char *keyword, -+ struct configFileInfo *cfi); -+static struct singleLine *getLineByType(enum lineType_e type, -+ struct singleLine *line); -+static int checkForExtLinux(struct grubConfig *config); -+struct singleLine *addLineTmpl(struct singleEntry *entry, -+ struct singleLine *tmplLine, -+ struct singleLine *prevLine, -+ const char *val, struct configFileInfo *cfi); -+struct singleLine *addLine(struct singleEntry *entry, -+ struct configFileInfo *cfi, -+ enum lineType_e type, char *defaultIndent, -+ const char *val); -+ -+static char *sdupprintf(const char *format, ...) - #ifdef __GNUC__ -- __attribute__ ((format (printf, 1, 2))); -+ __attribute__ ((format(printf, 1, 2))); - #else -- ; -+; - #endif - --static char * sdupprintf(const char *format, ...) { -- char *buf = NULL; -- char c; -- va_list args; -- size_t size = 0; -- va_start(args, format); -- -- /* XXX requires C99 vsnprintf behavior */ -- size = vsnprintf(&c, 1, format, args) + 1; -- if (size == -1) { -- printf("ERROR: vsnprintf behavior is not C99\n"); -- abort(); -- } -- -- va_end(args); -- va_start(args, format); -- -- buf = malloc(size); -- if (buf == NULL) -- return NULL; -- vsnprintf(buf, size, format, args); -- va_end (args); -+static char *sdupprintf(const char *format, ...) -+{ -+ char *buf = NULL; -+ char c; -+ va_list args; -+ size_t size = 0; -+ va_start(args, format); -+ -+ /* XXX requires C99 vsnprintf behavior */ -+ size = vsnprintf(&c, 1, format, args) + 1; -+ if (size == -1) { -+ printf("ERROR: vsnprintf behavior is not C99\n"); -+ abort(); -+ } - -- return buf; -+ va_end(args); -+ va_start(args, format); -+ -+ buf = malloc(size); -+ if (buf == NULL) -+ return NULL; -+ vsnprintf(buf, size, format, args); -+ va_end(args); -+ -+ return buf; - } - - static enum lineType_e preferredLineType(enum lineType_e type, -- struct configFileInfo *cfi) { -- if (isEfi && cfi == &grub2ConfigType) { -- switch (type) { -- case LT_KERNEL: -- return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI; -- case LT_INITRD: -- return isEfiOnly ? LT_INITRD : LT_INITRD_EFI; -- default: -- return type; -- } -+ struct configFileInfo *cfi) -+{ -+ if (isEfi && cfi == &grub2ConfigType) { -+ switch (type) { -+ case LT_KERNEL: -+ return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI; -+ case LT_INITRD: -+ return isEfiOnly ? LT_INITRD : LT_INITRD_EFI; -+ default: -+ return type; -+ } - #if defined(__i386__) || defined(__x86_64__) -- } else if (cfi == &grub2ConfigType) { -- switch (type) { -- case LT_KERNEL: -- return LT_KERNEL_16; -- case LT_INITRD: -- return LT_INITRD_16; -- default: -- return type; -- } -+ } else if (cfi == &grub2ConfigType) { -+ switch (type) { -+ case LT_KERNEL: -+ return LT_KERNEL_16; -+ case LT_INITRD: -+ return LT_INITRD_16; -+ default: -+ return type; -+ } - #endif -- } -- return type; -+ } -+ return type; - } - --static struct keywordTypes * getKeywordByType(enum lineType_e type, -- struct configFileInfo * cfi) { -- for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) { -- if (kw->type == type) -- return kw; -- } -- return NULL; -+static struct keywordTypes *getKeywordByType(enum lineType_e type, -+ struct configFileInfo *cfi) -+{ -+ for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) { -+ if (kw->type == type) -+ return kw; -+ } -+ return NULL; - } - --static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) { -- struct keywordTypes *kt = getKeywordByType(type, cfi); -- if (kt) -- return kt->key; -- return "unknown"; -+static char *getKeyByType(enum lineType_e type, struct configFileInfo *cfi) -+{ -+ struct keywordTypes *kt = getKeywordByType(type, cfi); -+ if (kt) -+ return kt->key; -+ return "unknown"; - } - --static char * getpathbyspec(char *device) { -- if (!blkid) -- blkid_get_cache(&blkid, NULL); -+static char *getpathbyspec(char *device) -+{ -+ if (!blkid) -+ blkid_get_cache(&blkid, NULL); - -- return blkid_get_devname(blkid, device, NULL); -+ return blkid_get_devname(blkid, device, NULL); - } - --static char * getuuidbydev(char *device) { -- if (!blkid) -- blkid_get_cache(&blkid, NULL); -+static char *getuuidbydev(char *device) -+{ -+ if (!blkid) -+ blkid_get_cache(&blkid, NULL); - -- return blkid_get_tag_value(blkid, "UUID", device); -+ return blkid_get_tag_value(blkid, "UUID", device); - } - --static enum lineType_e getTypeByKeyword(char * keyword, -- struct configFileInfo * cfi) { -- for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) { -- if (cfi->caseInsensitive) { -- if (!strcasecmp(keyword, kw->key)) -- return kw->type; -- } else { -- if (!strcmp(keyword, kw->key)) -- return kw->type; -+static enum lineType_e getTypeByKeyword(char *keyword, -+ struct configFileInfo *cfi) -+{ -+ for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) { -+ if (cfi->caseInsensitive) { -+ if (!strcasecmp(keyword, kw->key)) -+ return kw->type; -+ } else { -+ if (!strcmp(keyword, kw->key)) -+ return kw->type; -+ } - } -- } -- return LT_UNKNOWN; -+ return LT_UNKNOWN; - } - --static struct singleLine * getLineByType(enum lineType_e type, -- struct singleLine * line) { -- dbgPrintf("getLineByType(%d): ", type); -- for (; line; line = line->next) { -- dbgPrintf("%d:%s ", line->type, -- line->numElements ? line->elements[0].item : "(empty)"); -- if (line->type & type) break; -- } -- dbgPrintf(line ? "\n" : " (failed)\n"); -- return line; -+static struct singleLine *getLineByType(enum lineType_e type, -+ struct singleLine *line) -+{ -+ dbgPrintf("getLineByType(%d): ", type); -+ for (; line; line = line->next) { -+ dbgPrintf("%d:%s ", line->type, -+ line->numElements ? line->elements[0]. -+ item : "(empty)"); -+ if (line->type & type) -+ break; -+ } -+ dbgPrintf(line ? "\n" : " (failed)\n"); -+ return line; - } - --static int isBracketedTitle(struct singleLine * line) { -- if (line->numElements == 1 && *line->elements[0].item == '[') { -- int len = strlen(line->elements[0].item); -- if (*(line->elements[0].item + len - 1) == ']') { -- /* FIXME: this is a hack... */ -- if (strcmp(line->elements[0].item, "[defaultboot]")) { -- return 1; -- } -- } -- } -- return 0; -+static int isBracketedTitle(struct singleLine *line) -+{ -+ if (line->numElements == 1 && *line->elements[0].item == '[') { -+ int len = strlen(line->elements[0].item); -+ if (*(line->elements[0].item + len - 1) == ']') { -+ /* FIXME: this is a hack... */ -+ if (strcmp(line->elements[0].item, "[defaultboot]")) { -+ return 1; -+ } -+ } -+ } -+ return 0; - } - --static int isEntryStart(struct singleLine * line, -- struct configFileInfo * cfi) { -- return line->type == cfi->entryStart || line->type == LT_OTHER || -- (cfi->titleBracketed && isBracketedTitle(line)); -+static int isEntryStart(struct singleLine *line, struct configFileInfo *cfi) -+{ -+ return line->type == cfi->entryStart || line->type == LT_OTHER || -+ (cfi->titleBracketed && isBracketedTitle(line)); - } - - /* extract the title from within brackets (for zipl) */ --static char * extractTitle(struct grubConfig *cfg, struct singleLine * line) { -- /* bracketed title... let's extract it */ -- char * title = NULL; -- if (line->type == LT_TITLE) { -- char *tmp = line->elements[cfg->cfi->titlePosition].item; -- if (cfg->cfi->titleBracketed) { -- tmp++; -- title = strdup(tmp); -- *(title + strlen(title) - 1) = '\0'; -- } else { -- title = strdup(tmp); -- } -- } else if (line->type == LT_MENUENTRY) -- title = strdup(line->elements[1].item); -- else -- return NULL; -- return title; -+static char *extractTitle(struct grubConfig *cfg, struct singleLine *line) -+{ -+ /* bracketed title... let's extract it */ -+ char *title = NULL; -+ if (line->type == LT_TITLE) { -+ char *tmp = line->elements[cfg->cfi->titlePosition].item; -+ if (cfg->cfi->titleBracketed) { -+ tmp++; -+ title = strdup(tmp); -+ *(title + strlen(title) - 1) = '\0'; -+ } else { -+ title = strdup(tmp); -+ } -+ } else if (line->type == LT_MENUENTRY) -+ title = strdup(line->elements[1].item); -+ else -+ return NULL; -+ return title; - } - --static int readFile(int fd, char ** bufPtr) { -- int alloced = 0, size = 0, i = 0; -- char * buf = NULL; -+static int readFile(int fd, char **bufPtr) -+{ -+ int alloced = 0, size = 0, i = 0; -+ char *buf = NULL; -+ -+ do { -+ size += i; -+ if ((size + 1024) > alloced) { -+ alloced += 4096; -+ buf = realloc(buf, alloced + 1); -+ } -+ } while ((i = read(fd, buf + size, 1024)) > 0); - -- do { -- size += i; -- if ((size + 1024) > alloced) { -- alloced += 4096; -- buf = realloc(buf, alloced + 1); -+ if (i < 0) { -+ fprintf(stderr, _("error reading input: %s\n"), -+ strerror(errno)); -+ free(buf); -+ return 1; - } -- } while ((i = read(fd, buf + size, 1024)) > 0); -- -- if (i < 0) { -- fprintf(stderr, _("error reading input: %s\n"), strerror(errno)); -- free(buf); -- return 1; -- } - -- buf = realloc(buf, size + 2); -- if (size == 0) -- buf[size++] = '\n'; -- else -- if (buf[size - 1] != '\n') -- buf[size++] = '\n'; -- buf[size] = '\0'; -+ buf = realloc(buf, size + 2); -+ if (size == 0) -+ buf[size++] = '\n'; -+ else if (buf[size - 1] != '\n') -+ buf[size++] = '\n'; -+ buf[size] = '\0'; - -- *bufPtr = buf; -+ *bufPtr = buf; - -- return 0; -+ return 0; - } - --static void lineInit(struct singleLine * line) { -- line->indent = NULL; -- line->elements = NULL; -- line->numElements = 0; -- line->next = NULL; -+static void lineInit(struct singleLine *line) -+{ -+ line->indent = NULL; -+ line->elements = NULL; -+ line->numElements = 0; -+ line->next = NULL; - } - --struct singleLine * lineDup(struct singleLine * line) { -- struct singleLine * newLine = malloc(sizeof(*newLine)); -- -- newLine->indent = strdup(line->indent); -- newLine->next = NULL; -- newLine->type = line->type; -- newLine->numElements = line->numElements; -- newLine->elements = malloc(sizeof(*newLine->elements) * -- newLine->numElements); -- -- for (int i = 0; i < newLine->numElements; i++) { -- newLine->elements[i].indent = strdup(line->elements[i].indent); -- newLine->elements[i].item = strdup(line->elements[i].item); -- } -+struct singleLine *lineDup(struct singleLine *line) -+{ -+ struct singleLine *newLine = malloc(sizeof(*newLine)); -+ -+ newLine->indent = strdup(line->indent); -+ newLine->next = NULL; -+ newLine->type = line->type; -+ newLine->numElements = line->numElements; -+ newLine->elements = malloc(sizeof(*newLine->elements) * -+ newLine->numElements); -+ -+ for (int i = 0; i < newLine->numElements; i++) { -+ newLine->elements[i].indent = strdup(line->elements[i].indent); -+ newLine->elements[i].item = strdup(line->elements[i].item); -+ } - -- return newLine; -+ return newLine; - } - --static void lineFree(struct singleLine * line) { -- if (line->indent) free(line->indent); -+static void lineFree(struct singleLine *line) -+{ -+ if (line->indent) -+ free(line->indent); - -- for (int i = 0; i < line->numElements; i++) { -- free(line->elements[i].item); -- free(line->elements[i].indent); -- } -+ for (int i = 0; i < line->numElements; i++) { -+ free(line->elements[i].item); -+ free(line->elements[i].indent); -+ } - -- if (line->elements) free(line->elements); -- lineInit(line); -+ if (line->elements) -+ free(line->elements); -+ lineInit(line); - } - --static int lineWrite(FILE * out, struct singleLine * line, -- struct configFileInfo * cfi) { -- if (fprintf(out, "%s", line->indent) == -1) return -1; -- -- for (int i = 0; i < line->numElements; i++) { -- /* Need to handle this, because we strip the quotes from -- * menuentry when read it. */ -- if (line->type == LT_MENUENTRY && i == 1) { -- if(!isquote(*line->elements[i].item)) { -- int substring = 0; -- /* If the line contains nested quotes, we did not strip -- * the "interna" quotes and we must use the right quotes -- * again when writing the updated file. */ -- for (int j = i; j < line->numElements; j++) { -- if (strchr(line->elements[i].item, '\'') != NULL) { -- substring = 1; -- fprintf(out, "\"%s\"", line->elements[i].item); -- break; -- } -- } -- if (!substring) -- fprintf(out, "\'%s\'", line->elements[i].item); -- } else { -- fprintf(out, "%s", line->elements[i].item); -- } -- fprintf(out, "%s", line->elements[i].indent); -+static int lineWrite(FILE * out, struct singleLine *line, -+ struct configFileInfo *cfi) -+{ -+ if (fprintf(out, "%s", line->indent) == -1) -+ return -1; -+ -+ for (int i = 0; i < line->numElements; i++) { -+ /* Need to handle this, because we strip the quotes from -+ * menuentry when read it. */ -+ if (line->type == LT_MENUENTRY && i == 1) { -+ if (!isquote(*line->elements[i].item)) { -+ int substring = 0; -+ /* If the line contains nested quotes, we did not strip -+ * the "interna" quotes and we must use the right quotes -+ * again when writing the updated file. */ -+ for (int j = i; j < line->numElements; j++) { -+ if (strchr(line->elements[i].item, '\'') -+ != NULL) { -+ substring = 1; -+ fprintf(out, "\"%s\"", -+ line->elements[i].item); -+ break; -+ } -+ } -+ if (!substring) -+ fprintf(out, "\'%s\'", -+ line->elements[i].item); -+ } else { -+ fprintf(out, "%s", line->elements[i].item); -+ } -+ fprintf(out, "%s", line->elements[i].indent); - -- continue; -- } -+ continue; -+ } - -- if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes) -- if (fputc('"', out) == EOF) return -1; -+ if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes) -+ if (fputc('"', out) == EOF) -+ return -1; - -- if (fprintf(out, "%s", line->elements[i].item) == -1) return -1; -- if (i < line->numElements - 1) -- if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1; -- } -+ if (fprintf(out, "%s", line->elements[i].item) == -1) -+ return -1; -+ if (i < line->numElements - 1) -+ if (fprintf(out, "%s", line->elements[i].indent) == -1) -+ return -1; -+ } - -- if (line->type == LT_KERNELARGS && cfi->argsInQuotes) -- if (fputc('"', out) == EOF) return -1; -+ if (line->type == LT_KERNELARGS && cfi->argsInQuotes) -+ if (fputc('"', out) == EOF) -+ return -1; - -- if (fprintf(out, "\n") == -1) return -1; -+ if (fprintf(out, "\n") == -1) -+ return -1; - -- return 0; -+ return 0; - } - - /* we've guaranteed that the buffer ends w/ \n\0 */ --static int getNextLine(char ** bufPtr, struct singleLine * line, -- struct configFileInfo * cfi) { -- char * end; -- char * start = *bufPtr; -- char * chptr; -- int elementsAlloced = 0; -- struct lineElement * element; -- int first = 1; -- -- lineFree(line); -+static int getNextLine(char **bufPtr, struct singleLine *line, -+ struct configFileInfo *cfi) -+{ -+ char *end; -+ char *start = *bufPtr; -+ char *chptr; -+ int elementsAlloced = 0; -+ struct lineElement *element; -+ int first = 1; - -- end = strchr(start, '\n'); -- *end = '\0'; -- *bufPtr = end + 1; -+ lineFree(line); - -- for (chptr = start; *chptr && isspace(*chptr); chptr++) ; -+ end = strchr(start, '\n'); -+ *end = '\0'; -+ *bufPtr = end + 1; - -- line->indent = strndup(start, chptr - start); -- start = chptr; -+ for (chptr = start; *chptr && isspace(*chptr); chptr++) ; - -- while (start < end) { -- /* we know !isspace(*start) */ -+ line->indent = strndup(start, chptr - start); -+ start = chptr; - -- if (elementsAlloced == line->numElements) { -- elementsAlloced += 5; -- line->elements = realloc(line->elements, -- sizeof(*line->elements) * elementsAlloced); -- } -+ while (start < end) { -+ /* we know !isspace(*start) */ - -- element = line->elements + line->numElements; -+ if (elementsAlloced == line->numElements) { -+ elementsAlloced += 5; -+ line->elements = realloc(line->elements, -+ sizeof(*line->elements) * -+ elementsAlloced); -+ } - -- chptr = start; -- while (*chptr && !isspace(*chptr)) { -- if (first && *chptr == '=') break; -- chptr++; -- } -- element->item = strndup(start, chptr - start); -- start = chptr; -+ element = line->elements + line->numElements; - -- /* lilo actually accepts the pathological case of append = " foo " */ -- if (*start == '=') -- chptr = start + 1; -- else -- chptr = start; -+ chptr = start; -+ while (*chptr && !isspace(*chptr)) { -+ if (first && *chptr == '=') -+ break; -+ chptr++; -+ } -+ element->item = strndup(start, chptr - start); -+ start = chptr; - -- do { -- for (; *chptr && isspace(*chptr); chptr++); -- if (*chptr == '=') -- chptr = chptr + 1; -- } while (isspace(*chptr)); -+ /* lilo actually accepts the pathological case of append = " foo " */ -+ if (*start == '=') -+ chptr = start + 1; -+ else -+ chptr = start; - -- element->indent = strndup(start, chptr - start); -- start = chptr; -+ do { -+ for (; *chptr && isspace(*chptr); chptr++) ; -+ if (*chptr == '=') -+ chptr = chptr + 1; -+ } while (isspace(*chptr)); - -- line->numElements++; -- first = 0; -- } -- -- if (!line->numElements) -- line->type = LT_WHITESPACE; -- else { -- line->type = getTypeByKeyword(line->elements[0].item, cfi); -- if (line->type == LT_UNKNOWN) { -- /* zipl does [title] instead of something reasonable like all -- * the other boot loaders. kind of ugly */ -- if (cfi->titleBracketed && isBracketedTitle(line)) { -- line->type = LT_TITLE; -- } -- -- /* this is awkward, but we need to be able to handle keywords -- that begin with a # (specifically for #boot in grub.conf), -- but still make comments lines with no elements (everything -- stored in the indent */ -- if (*line->elements[0].item == '#') { -- char * fullLine; -- int len; -- -- len = strlen(line->indent); -- for (int i = 0; i < line->numElements; i++) -- len += strlen(line->elements[i].item) + -- strlen(line->elements[i].indent); -- -- fullLine = malloc(len + 1); -- strcpy(fullLine, line->indent); -- free(line->indent); -- line->indent = fullLine; -+ element->indent = strndup(start, chptr - start); -+ start = chptr; - -- for (int i = 0; i < line->numElements; i++) { -- strcat(fullLine, line->elements[i].item); -- strcat(fullLine, line->elements[i].indent); -- free(line->elements[i].item); -- free(line->elements[i].indent); -- } -+ line->numElements++; -+ first = 0; -+ } - -+ if (!line->numElements) - line->type = LT_WHITESPACE; -- line->numElements = 0; -- } -- } else { -- struct keywordTypes *kw; -+ else { -+ line->type = getTypeByKeyword(line->elements[0].item, cfi); -+ if (line->type == LT_UNKNOWN) { -+ /* zipl does [title] instead of something reasonable like all -+ * the other boot loaders. kind of ugly */ -+ if (cfi->titleBracketed && isBracketedTitle(line)) { -+ line->type = LT_TITLE; -+ } - -- kw = getKeywordByType(line->type, cfi); -+ /* this is awkward, but we need to be able to handle keywords -+ that begin with a # (specifically for #boot in grub.conf), -+ but still make comments lines with no elements (everything -+ stored in the indent */ -+ if (*line->elements[0].item == '#') { -+ char *fullLine; -+ int len; -+ -+ len = strlen(line->indent); -+ for (int i = 0; i < line->numElements; i++) -+ len += strlen(line->elements[i].item) + -+ strlen(line->elements[i].indent); -+ -+ fullLine = malloc(len + 1); -+ strcpy(fullLine, line->indent); -+ free(line->indent); -+ line->indent = fullLine; -+ -+ for (int i = 0; i < line->numElements; i++) { -+ strcat(fullLine, -+ line->elements[i].item); -+ strcat(fullLine, -+ line->elements[i].indent); -+ free(line->elements[i].item); -+ free(line->elements[i].indent); -+ } - -- /* space isn't the only separator, we need to split -- * elements up more -- */ -- if (!isspace(kw->separatorChar)) { -- char indent[2] = ""; -- indent[0] = kw->separatorChar; -- for (int i = 1; i < line->numElements; i++) { -- char *p; -- int numNewElements; -- -- numNewElements = 0; -- p = line->elements[i].item; -- while (*p != '\0') { -- if (*p == kw->separatorChar) -- numNewElements++; -- p++; -- } -- if (line->numElements + numNewElements >= elementsAlloced) { -- elementsAlloced += numNewElements + 5; -- line->elements = realloc(line->elements, -- sizeof(*line->elements) * elementsAlloced); -+ line->type = LT_WHITESPACE; -+ line->numElements = 0; - } -+ } else { -+ struct keywordTypes *kw; - -- for (int j = line->numElements; j > i; j--) { -- line->elements[j + numNewElements] = line->elements[j]; -- } -- line->numElements += numNewElements; -+ kw = getKeywordByType(line->type, cfi); - -- p = line->elements[i].item; -- while (*p != '\0') { -+ /* space isn't the only separator, we need to split -+ * elements up more -+ */ -+ if (!isspace(kw->separatorChar)) { -+ char indent[2] = ""; -+ indent[0] = kw->separatorChar; -+ for (int i = 1; i < line->numElements; i++) { -+ char *p; -+ int numNewElements; -+ -+ numNewElements = 0; -+ p = line->elements[i].item; -+ while (*p != '\0') { -+ if (*p == kw->separatorChar) -+ numNewElements++; -+ p++; -+ } -+ if (line->numElements + -+ numNewElements >= elementsAlloced) { -+ elementsAlloced += -+ numNewElements + 5; -+ line->elements = -+ realloc(line->elements, -+ sizeof(*line-> -+ elements) * -+ elementsAlloced); -+ } - -- while (*p != kw->separatorChar && *p != '\0') p++; -- if (*p == '\0') { -- break; -+ for (int j = line->numElements; j > i; -+ j--) { -+ line->elements[j + -+ numNewElements] = -+ line->elements[j]; -+ } -+ line->numElements += numNewElements; -+ -+ p = line->elements[i].item; -+ while (*p != '\0') { -+ -+ while (*p != kw->separatorChar -+ && *p != '\0') -+ p++; -+ if (*p == '\0') { -+ break; -+ } -+ -+ line->elements[i + 1].indent = -+ line->elements[i].indent; -+ line->elements[i].indent = -+ strdup(indent); -+ *p++ = '\0'; -+ i++; -+ line->elements[i].item = -+ strdup(p); -+ } - } -- -- line->elements[i + 1].indent = line->elements[i].indent; -- line->elements[i].indent = strdup(indent); -- *p++ = '\0'; -- i++; -- line->elements[i].item = strdup(p); - } -- } - } - } -- } - -- return 0; -+ return 0; - } - - static int isnumber(const char *s) - { -- int i; -- for (i = 0; s[i] != '\0'; i++) -- if (s[i] < '0' || s[i] > '9') -- return 0; -- return i; -+ int i; -+ for (i = 0; s[i] != '\0'; i++) -+ if (s[i] < '0' || s[i] > '9') -+ return 0; -+ return i; - } - --static struct grubConfig * readConfig(const char * inName, -- struct configFileInfo * cfi) { -- int in; -- char * incoming = NULL, * head; -- int rc; -- int sawEntry = 0; -- int movedLine = 0; -- struct grubConfig * cfg; -- struct singleLine * last = NULL, * line, * defaultLine = NULL; -- char * end; -- struct singleEntry * entry = NULL; -- int len; -- char * buf; -- -- if (inName == NULL) { -- printf("Could not find bootloader configuration\n"); -- exit(1); -- } else if (!strcmp(inName, "-")) { -- in = 0; -- } else { -- if ((in = open(inName, O_RDONLY)) < 0) { -- fprintf(stderr, _("error opening %s for read: %s\n"), -- inName, strerror(errno)); -- return NULL; -- } -- } -- -- rc = readFile(in, &incoming); -- close(in); -- if (rc) return NULL; -- -- head = incoming; -- cfg = malloc(sizeof(*cfg)); -- cfg->primaryIndent = strdup(""); -- cfg->secondaryIndent = strdup("\t"); -- cfg->flags = GRUB_CONFIG_NO_DEFAULT; -- cfg->cfi = cfi; -- cfg->theLines = NULL; -- cfg->entries = NULL; -- cfg->fallbackImage = 0; -- -- /* copy everything we have */ -- while (*head) { -- line = malloc(sizeof(*line)); -- lineInit(line); -- -- if (getNextLine(&head, line, cfi)) { -- free(line); -- /* XXX memory leak of everything in cfg */ -- return NULL; -- } -- -- if (!sawEntry && line->numElements) { -- free(cfg->primaryIndent); -- cfg->primaryIndent = strdup(line->indent); -- } else if (line->numElements) { -- free(cfg->secondaryIndent); -- cfg->secondaryIndent = strdup(line->indent); -+static struct grubConfig *readConfig(const char *inName, -+ struct configFileInfo *cfi) -+{ -+ int in; -+ char *incoming = NULL, *head; -+ int rc; -+ int sawEntry = 0; -+ int movedLine = 0; -+ struct grubConfig *cfg; -+ struct singleLine *last = NULL, *line, *defaultLine = NULL; -+ char *end; -+ struct singleEntry *entry = NULL; -+ int len; -+ char *buf; -+ -+ if (inName == NULL) { -+ printf("Could not find bootloader configuration\n"); -+ exit(1); -+ } else if (!strcmp(inName, "-")) { -+ in = 0; -+ } else { -+ if ((in = open(inName, O_RDONLY)) < 0) { -+ fprintf(stderr, _("error opening %s for read: %s\n"), -+ inName, strerror(errno)); -+ return NULL; -+ } - } - -- if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) { -- sawEntry = 1; -- if (!entry) { -- cfg->entries = malloc(sizeof(*entry)); -- entry = cfg->entries; -- } else { -- entry->next = malloc(sizeof(*entry)); -- entry = entry->next; -- } -- -- entry->skip = 0; -- entry->multiboot = 0; -- entry->lines = NULL; -- entry->next = NULL; -- } -- -- if (line->type == LT_SET_VARIABLE) { -- dbgPrintf("found 'set' command (%d elements): ", line->numElements); -- dbgPrintf("%s", line->indent); -- for (int i = 0; i < line->numElements; i++) -- dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent); -- dbgPrintf("\n"); -- struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi); -- if (kwType && line->numElements == 3 && -- !strcmp(line->elements[1].item, kwType->key) && -- !is_special_grub2_variable(line->elements[2].item)) { -- dbgPrintf("Line sets default config\n"); -- cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; -- defaultLine = line; -- } -- -- } else if (iskernel(line->type)) { -- /* if by some freak chance this is multiboot and the "module" -- * lines came earlier in the template, make sure to use LT_HYPER -- * instead of LT_KERNEL now -- */ -- if (entry && entry->multiboot) -- line->type = LT_HYPER; -- -- } else if (line->type == LT_MBMODULE) { -- /* go back and fix the LT_KERNEL line to indicate LT_HYPER -- * instead, now that we know this is a multiboot entry. -- * This only applies to grub, but that's the only place we -- * should find LT_MBMODULE lines anyway. -- */ -- for (struct singleLine *l = entry->lines; l; l = l->next) { -- if (l->type == LT_HYPER) -- break; -- else if (iskernel(l->type)) { -- l->type = LT_HYPER; -- break; -+ rc = readFile(in, &incoming); -+ close(in); -+ if (rc) -+ return NULL; -+ -+ head = incoming; -+ cfg = malloc(sizeof(*cfg)); -+ cfg->primaryIndent = strdup(""); -+ cfg->secondaryIndent = strdup("\t"); -+ cfg->flags = GRUB_CONFIG_NO_DEFAULT; -+ cfg->cfi = cfi; -+ cfg->theLines = NULL; -+ cfg->entries = NULL; -+ cfg->fallbackImage = 0; -+ -+ /* copy everything we have */ -+ while (*head) { -+ line = malloc(sizeof(*line)); -+ lineInit(line); -+ -+ if (getNextLine(&head, line, cfi)) { -+ free(line); -+ /* XXX memory leak of everything in cfg */ -+ return NULL; - } -- } -- entry->multiboot = 1; -- -- } else if (line->type == LT_HYPER) { -- entry->multiboot = 1; -- -- } else if (line->type == LT_FALLBACK && line->numElements == 2) { -- cfg->fallbackImage = strtol(line->elements[1].item, &end, 10); -- if (*end) cfg->fallbackImage = -1; -- -- } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) || -- (line->type == LT_TITLE && line->numElements > 1)) { -- /* make the title/default a single argument (undoing our parsing) */ -- len = 0; -- for (int i = 1; i < line->numElements; i++) { -- len += strlen(line->elements[i].item); -- len += strlen(line->elements[i].indent); -- } -- buf = malloc(len + 1); -- *buf = '\0'; -- -- for (int i = 1; i < line->numElements; i++) { -- strcat(buf, line->elements[i].item); -- free(line->elements[i].item); - -- if ((i + 1) != line->numElements) { -- strcat(buf, line->elements[i].indent); -- free(line->elements[i].indent); -- } -- } -- -- line->elements[1].indent = -- line->elements[line->numElements - 1].indent; -- line->elements[1].item = buf; -- line->numElements = 2; -- } else if (line->type == LT_MENUENTRY && line->numElements > 3) { -- /* let --remove-kernel="TITLE=what" work */ -- len = 0; -- char *extras; -- char *title; -- /* initially unseen value */ -- char quote_char = '\0'; -- -- for (int i = 1; i < line->numElements; i++) { -- len += strlen(line->elements[i].item); -- len += strlen(line->elements[i].indent); -- } -- buf = malloc(len + 1); -- *buf = '\0'; -- -- /* allocate mem for extra flags. */ -- extras = malloc(len + 1); -- *extras = '\0'; -- -- /* get title. */ -- for (int i = 0; i < line->numElements; i++) { -- if (!strcmp(line->elements[i].item, "menuentry")) -- continue; -- if (isquote(*line->elements[i].item) && quote_char == '\0') { -- /* ensure we properly pair off quotes */ -- quote_char = *line->elements[i].item; -- title = line->elements[i].item + 1; -- } else { -- title = line->elements[i].item; -+ if (!sawEntry && line->numElements) { -+ free(cfg->primaryIndent); -+ cfg->primaryIndent = strdup(line->indent); -+ } else if (line->numElements) { -+ free(cfg->secondaryIndent); -+ cfg->secondaryIndent = strdup(line->indent); - } - -- len = strlen(title); -- if (title[len-1] == quote_char) { -- strncat(buf, title,len-1); -- break; -- } else { -- strcat(buf, title); -- strcat(buf, line->elements[i].indent); -- } -- } -- -- /* get extras */ -- int count = 0; -- quote_char = '\0'; -- for (int i = 0; i < line->numElements; i++) { -- if (count >= 2) { -- strcat(extras, line->elements[i].item); -- strcat(extras, line->elements[i].indent); -+ if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) { -+ sawEntry = 1; -+ if (!entry) { -+ cfg->entries = malloc(sizeof(*entry)); -+ entry = cfg->entries; -+ } else { -+ entry->next = malloc(sizeof(*entry)); -+ entry = entry->next; -+ } -+ -+ entry->skip = 0; -+ entry->multiboot = 0; -+ entry->lines = NULL; -+ entry->next = NULL; - } - -- if (!strcmp(line->elements[i].item, "menuentry")) -- continue; -+ if (line->type == LT_SET_VARIABLE) { -+ dbgPrintf("found 'set' command (%d elements): ", -+ line->numElements); -+ dbgPrintf("%s", line->indent); -+ for (int i = 0; i < line->numElements; i++) -+ dbgPrintf("\"%s\"%s", line->elements[i].item, -+ line->elements[i].indent); -+ dbgPrintf("\n"); -+ struct keywordTypes *kwType = -+ getKeywordByType(LT_DEFAULT, cfi); -+ if (kwType && line->numElements == 3 -+ && !strcmp(line->elements[1].item, kwType->key) -+ && !is_special_grub2_variable(line->elements[2]. -+ item)) { -+ dbgPrintf("Line sets default config\n"); -+ cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; -+ defaultLine = line; -+ } -+ -+ } else if (iskernel(line->type)) { -+ /* if by some freak chance this is multiboot and the "module" -+ * lines came earlier in the template, make sure to use LT_HYPER -+ * instead of LT_KERNEL now -+ */ -+ if (entry && entry->multiboot) -+ line->type = LT_HYPER; -+ -+ } else if (line->type == LT_MBMODULE) { -+ /* go back and fix the LT_KERNEL line to indicate LT_HYPER -+ * instead, now that we know this is a multiboot entry. -+ * This only applies to grub, but that's the only place we -+ * should find LT_MBMODULE lines anyway. -+ */ -+ for (struct singleLine * l = entry->lines; l; -+ l = l->next) { -+ if (l->type == LT_HYPER) -+ break; -+ else if (iskernel(l->type)) { -+ l->type = LT_HYPER; -+ break; -+ } -+ } -+ entry->multiboot = 1; -+ -+ } else if (line->type == LT_HYPER) { -+ entry->multiboot = 1; -+ -+ } else if (line->type == LT_FALLBACK && line->numElements == 2) { -+ cfg->fallbackImage = -+ strtol(line->elements[1].item, &end, 10); -+ if (*end) -+ cfg->fallbackImage = -1; -+ -+ } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) -+ || (line->type == LT_TITLE -+ && line->numElements > 1)) { -+ /* make the title/default a single argument (undoing our parsing) */ -+ len = 0; -+ for (int i = 1; i < line->numElements; i++) { -+ len += strlen(line->elements[i].item); -+ len += strlen(line->elements[i].indent); -+ } -+ buf = malloc(len + 1); -+ *buf = '\0'; -+ -+ for (int i = 1; i < line->numElements; i++) { -+ strcat(buf, line->elements[i].item); -+ free(line->elements[i].item); -+ -+ if ((i + 1) != line->numElements) { -+ strcat(buf, line->elements[i].indent); -+ free(line->elements[i].indent); -+ } -+ } -+ -+ line->elements[1].indent = -+ line->elements[line->numElements - 1].indent; -+ line->elements[1].item = buf; -+ line->numElements = 2; -+ } else if (line->type == LT_MENUENTRY && line->numElements > 3) { -+ /* let --remove-kernel="TITLE=what" work */ -+ len = 0; -+ char *extras; -+ char *title; -+ /* initially unseen value */ -+ char quote_char = '\0'; -+ -+ for (int i = 1; i < line->numElements; i++) { -+ len += strlen(line->elements[i].item); -+ len += strlen(line->elements[i].indent); -+ } -+ buf = malloc(len + 1); -+ *buf = '\0'; -+ -+ /* allocate mem for extra flags. */ -+ extras = malloc(len + 1); -+ *extras = '\0'; -+ -+ /* get title. */ -+ for (int i = 0; i < line->numElements; i++) { -+ if (!strcmp -+ (line->elements[i].item, "menuentry")) -+ continue; -+ if (isquote(*line->elements[i].item) -+ && quote_char == '\0') { -+ /* ensure we properly pair off quotes */ -+ quote_char = *line->elements[i].item; -+ title = line->elements[i].item + 1; -+ } else { -+ title = line->elements[i].item; -+ } -+ -+ len = strlen(title); -+ if (title[len - 1] == quote_char) { -+ strncat(buf, title, len - 1); -+ break; -+ } else { -+ strcat(buf, title); -+ strcat(buf, line->elements[i].indent); -+ } -+ } -+ -+ /* get extras */ -+ int count = 0; -+ quote_char = '\0'; -+ for (int i = 0; i < line->numElements; i++) { -+ if (count >= 2) { -+ strcat(extras, line->elements[i].item); -+ strcat(extras, -+ line->elements[i].indent); -+ } -+ -+ if (!strcmp -+ (line->elements[i].item, "menuentry")) -+ continue; - -- /* count ' or ", there should be two in menuentry line. */ -- if (isquote(*line->elements[i].item) && quote_char == '\0') { -- /* ensure we properly pair off quotes */ -- quote_char = *line->elements[i].item; -- count++; -+ /* count ' or ", there should be two in menuentry line. */ -+ if (isquote(*line->elements[i].item) -+ && quote_char == '\0') { -+ /* ensure we properly pair off quotes */ -+ quote_char = *line->elements[i].item; -+ count++; -+ } -+ -+ len = strlen(line->elements[i].item); -+ -+ if (line->elements[i].item[len - 1] == -+ quote_char) -+ count++; -+ -+ /* ok, we get the final ' or ", others are extras. */ -+ } -+ line->elements[1].indent = -+ line->elements[line->numElements - 2].indent; -+ line->elements[1].item = buf; -+ line->elements[2].indent = -+ line->elements[line->numElements - 2].indent; -+ line->elements[2].item = extras; -+ line->numElements = 3; -+ } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) { -+ /* Strip off any " which may be present; they'll be put back -+ on write. This is one of the few (the only?) places that grubby -+ canonicalizes the output */ -+ -+ if (line->numElements >= 2) { -+ int last, len; -+ -+ if (isquote(*line->elements[1].item)) -+ memmove(line->elements[1].item, -+ line->elements[1].item + 1, -+ strlen(line->elements[1].item + -+ 1) + 1); -+ -+ last = line->numElements - 1; -+ len = strlen(line->elements[last].item) - 1; -+ if (isquote(line->elements[last].item[len])) -+ line->elements[last].item[len] = '\0'; -+ } - } - -- len = strlen(line->elements[i].item); -- -- if (line->elements[i].item[len -1] == quote_char) -- count++; -- -- /* ok, we get the final ' or ", others are extras. */ -- } -- line->elements[1].indent = -- line->elements[line->numElements - 2].indent; -- line->elements[1].item = buf; -- line->elements[2].indent = -- line->elements[line->numElements - 2].indent; -- line->elements[2].item = extras; -- line->numElements = 3; -- } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) { -- /* Strip off any " which may be present; they'll be put back -- on write. This is one of the few (the only?) places that grubby -- canonicalizes the output */ -- -- if (line->numElements >= 2) { -- int last, len; -- -- if (isquote(*line->elements[1].item)) -- memmove(line->elements[1].item, line->elements[1].item + 1, -- strlen(line->elements[1].item + 1) + 1); -- -- last = line->numElements - 1; -- len = strlen(line->elements[last].item) - 1; -- if (isquote(line->elements[last].item[len])) -- line->elements[last].item[len] = '\0'; -- } -- } -- -- if (line->type == LT_DEFAULT && line->numElements == 2) { -- cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; -- defaultLine = line; -- } -- -- /* If we find a generic config option which should live at the -- top of the file, move it there. Old versions of grubby were -- probably responsible for putting new images in the wrong -- place in front of it anyway. */ -- if (sawEntry && line->type == LT_GENERIC) { -- struct singleLine **l = &cfg->theLines; -- struct singleLine **last_nonws = &cfg->theLines; -- while (*l) { -- if ((*l)->type != LT_WHITESPACE) -- last_nonws = &((*l)->next); -- l = &((*l)->next); -+ if (line->type == LT_DEFAULT && line->numElements == 2) { -+ cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; -+ defaultLine = line; - } -- line->next = *last_nonws; -- *last_nonws = line; -- movedLine = 1; -- continue; /* without setting 'last' */ -- } - -- /* If a second line of whitespace happens after a generic option -- which was moved, drop it. */ -- if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) { -- lineFree(line); -- free(line); -+ /* If we find a generic config option which should live at the -+ top of the file, move it there. Old versions of grubby were -+ probably responsible for putting new images in the wrong -+ place in front of it anyway. */ -+ if (sawEntry && line->type == LT_GENERIC) { -+ struct singleLine **l = &cfg->theLines; -+ struct singleLine **last_nonws = &cfg->theLines; -+ while (*l) { -+ if ((*l)->type != LT_WHITESPACE) -+ last_nonws = &((*l)->next); -+ l = &((*l)->next); -+ } -+ line->next = *last_nonws; -+ *last_nonws = line; -+ movedLine = 1; -+ continue; /* without setting 'last' */ -+ } -+ -+ /* If a second line of whitespace happens after a generic option -+ which was moved, drop it. */ -+ if (movedLine && line->type == LT_WHITESPACE -+ && last->type == LT_WHITESPACE) { -+ lineFree(line); -+ free(line); -+ movedLine = 0; -+ continue; -+ } - movedLine = 0; -- continue; -- } -- movedLine = 0; - -- if (sawEntry) { -- if (!entry->lines) -- entry->lines = line; -- else -- last->next = line; -- dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry); -+ if (sawEntry) { -+ if (!entry->lines) -+ entry->lines = line; -+ else -+ last->next = line; -+ dbgPrintf("readConfig added %s to %p\n", -+ getKeyByType(line->type, cfi), entry); -+ -+ /* we could have seen this outside of an entry... if so, we -+ * ignore it like any other line we don't grok */ -+ if (line->type == LT_ENTRY_END && sawEntry) -+ sawEntry = 0; -+ } else { -+ if (!cfg->theLines) -+ cfg->theLines = line; -+ else -+ last->next = line; -+ dbgPrintf("readConfig added %s to cfg\n", -+ getKeyByType(line->type, cfi)); -+ } - -- /* we could have seen this outside of an entry... if so, we -- * ignore it like any other line we don't grok */ -- if (line->type == LT_ENTRY_END && sawEntry) -- sawEntry = 0; -- } else { -- if (!cfg->theLines) -- cfg->theLines = line; -- else -- last->next = line; -- dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi)); -+ last = line; - } - -- last = line; -- } -- -- free(incoming); -+ free(incoming); -+ -+ dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset"); -+ if (defaultLine) { -+ if (defaultLine->numElements > 2 && -+ cfi->defaultSupportSaved && -+ !strncmp(defaultLine->elements[2].item, -+ "\"${saved_entry}\"", 16)) { -+ cfg->cfi->defaultIsSaved = 1; -+ cfg->defaultImage = DEFAULT_SAVED_GRUB2; -+ if (cfg->cfi->getEnv) { -+ char *defTitle = -+ cfi->getEnv(cfg->cfi, "saved_entry"); -+ if (defTitle) { -+ int index = 0; -+ if (isnumber(defTitle)) { -+ index = atoi(defTitle); -+ entry = -+ findEntryByIndex(cfg, -+ index); -+ } else { -+ entry = -+ findEntryByTitle(cfg, -+ defTitle, -+ &index); -+ } -+ if (entry) -+ cfg->defaultImage = index; -+ } -+ } -+ } else if (cfi->defaultIsVariable) { -+ char *value = defaultLine->elements[2].item; -+ while (*value && (*value == '"' || *value == '\'' || -+ *value == ' ' || *value == '\t')) -+ value++; -+ cfg->defaultImage = strtol(value, &end, 10); -+ while (*end && (*end == '"' || *end == '\'' || -+ *end == ' ' || *end == '\t')) -+ end++; -+ if (*end) -+ cfg->defaultImage = -1; -+ } else if (cfi->defaultSupportSaved && -+ !strncmp(defaultLine->elements[1].item, "saved", -+ 5)) { -+ cfg->defaultImage = DEFAULT_SAVED; -+ } else if (cfi->defaultIsIndex) { -+ cfg->defaultImage = -+ strtol(defaultLine->elements[1].item, &end, 10); -+ if (*end) -+ cfg->defaultImage = -1; -+ } else if (defaultLine->numElements >= 2) { -+ int i = 0; -+ while ((entry = findEntryByIndex(cfg, i))) { -+ for (line = entry->lines; line; -+ line = line->next) -+ if (line->type == LT_TITLE) -+ break; -+ -+ if (!cfi->titleBracketed) { -+ if (line && (line->numElements >= 2) && -+ !strcmp(defaultLine->elements[1]. -+ item, -+ line->elements[1].item)) -+ break; -+ } else if (line) { -+ if (!strcmp -+ (defaultLine->elements[1].item, -+ extractTitle(cfg, line))) -+ break; -+ } -+ i++; -+ entry = NULL; -+ } - -- dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset"); -- if (defaultLine) { -- if (defaultLine->numElements > 2 && -- cfi->defaultSupportSaved && -- !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) { -- cfg->cfi->defaultIsSaved = 1; -- cfg->defaultImage = DEFAULT_SAVED_GRUB2; -- if (cfg->cfi->getEnv) { -- char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); -- if (defTitle) { -+ if (entry) { -+ cfg->defaultImage = i; -+ } else { -+ cfg->defaultImage = -1; -+ } -+ } -+ } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) { -+ char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); -+ if (defTitle) { - int index = 0; - if (isnumber(defTitle)) { -- index = atoi(defTitle); -- entry = findEntryByIndex(cfg, index); -+ index = atoi(defTitle); -+ entry = findEntryByIndex(cfg, index); - } else { -- entry = findEntryByTitle(cfg, defTitle, &index); -+ entry = findEntryByTitle(cfg, defTitle, &index); - } - if (entry) -- cfg->defaultImage = index; -- } -+ cfg->defaultImage = index; - } -- } else if (cfi->defaultIsVariable) { -- char *value = defaultLine->elements[2].item; -- while (*value && (*value == '"' || *value == '\'' || -- *value == ' ' || *value == '\t')) -- value++; -- cfg->defaultImage = strtol(value, &end, 10); -- while (*end && (*end == '"' || *end == '\'' || -- *end == ' ' || *end == '\t')) -- end++; -- if (*end) cfg->defaultImage = -1; -- } else if (cfi->defaultSupportSaved && -- !strncmp(defaultLine->elements[1].item, "saved", 5)) { -- cfg->defaultImage = DEFAULT_SAVED; -- } else if (cfi->defaultIsIndex) { -- cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10); -- if (*end) cfg->defaultImage = -1; -- } else if (defaultLine->numElements >= 2) { -- int i = 0; -- while ((entry = findEntryByIndex(cfg, i))) { -- for (line = entry->lines; line; line = line->next) -- if (line->type == LT_TITLE) break; -- -- if (!cfi->titleBracketed) { -- if (line && (line->numElements >= 2) && -- !strcmp(defaultLine->elements[1].item, -- line->elements[1].item)) break; -- } else if (line) { -- if (!strcmp(defaultLine->elements[1].item, -- extractTitle(cfg, line))) break; -- } -- i++; -- entry = NULL; -- } -- -- if (entry){ -- cfg->defaultImage = i; -- }else{ -- cfg->defaultImage = -1; -- } -- } -- } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) { -- char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); -- if (defTitle) { -- int index = 0; -- if (isnumber(defTitle)) { -- index = atoi(defTitle); -- entry = findEntryByIndex(cfg, index); -- } else { -- entry = findEntryByTitle(cfg, defTitle, &index); -- } -- if (entry) -- cfg->defaultImage = index; -- } -- } else { -- cfg->defaultImage = 0; -- } -- -- return cfg; -+ } else { -+ cfg->defaultImage = 0; -+ } -+ -+ return cfg; - } - --static void writeDefault(FILE * out, char * indent, -- char * separator, struct grubConfig * cfg) { -- struct singleEntry * entry; -- struct singleLine * line; -- int i; -- -- if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) -- return; -- -- if (cfg->defaultImage == DEFAULT_SAVED) -- fprintf(out, "%sdefault%ssaved\n", indent, separator); -- else if (cfg->cfi->defaultIsSaved) { -- fprintf(out, "%sset default=\"${saved_entry}\"\n", indent); -- if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) { -- char *title; -- entry = findEntryByIndex(cfg, cfg->defaultImage); -- line = getLineByType(LT_MENUENTRY, entry->lines); -- if (!line) -- line = getLineByType(LT_TITLE, entry->lines); -- if (line) { -- title = extractTitle(cfg, line); -- if (title) -- cfg->cfi->setEnv(cfg->cfi, "saved_entry", title); -- } -- } -- } else if (cfg->defaultImage > -1) { -- if (cfg->cfi->defaultIsIndex) { -- if (cfg->cfi->defaultIsVariable) { -- fprintf(out, "%sset default=\"%d\"\n", indent, -- cfg->defaultImage); -- } else { -- fprintf(out, "%sdefault%s%d\n", indent, separator, -- cfg->defaultImage); -- } -- } else { -- int image = cfg->defaultImage; -+static void writeDefault(FILE * out, char *indent, -+ char *separator, struct grubConfig *cfg) -+{ -+ struct singleEntry *entry; -+ struct singleLine *line; -+ int i; - -- entry = cfg->entries; -- while (entry && entry->skip) -- entry = entry->next; -+ if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) -+ return; - -- i = 0; -- while (entry && i < image) { -- entry = entry->next; -+ if (cfg->defaultImage == DEFAULT_SAVED) -+ fprintf(out, "%sdefault%ssaved\n", indent, separator); -+ else if (cfg->cfi->defaultIsSaved) { -+ fprintf(out, "%sset default=\"${saved_entry}\"\n", indent); -+ if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) { -+ char *title; -+ entry = findEntryByIndex(cfg, cfg->defaultImage); -+ line = getLineByType(LT_MENUENTRY, entry->lines); -+ if (!line) -+ line = getLineByType(LT_TITLE, entry->lines); -+ if (line) { -+ title = extractTitle(cfg, line); -+ if (title) -+ cfg->cfi->setEnv(cfg->cfi, -+ "saved_entry", title); -+ } -+ } -+ } else if (cfg->defaultImage > -1) { -+ if (cfg->cfi->defaultIsIndex) { -+ if (cfg->cfi->defaultIsVariable) { -+ fprintf(out, "%sset default=\"%d\"\n", indent, -+ cfg->defaultImage); -+ } else { -+ fprintf(out, "%sdefault%s%d\n", indent, -+ separator, cfg->defaultImage); -+ } -+ } else { -+ int image = cfg->defaultImage; - -- while (entry && entry->skip) -- entry = entry->next; -- i++; -- } -+ entry = cfg->entries; -+ while (entry && entry->skip) -+ entry = entry->next; - -- if (!entry) -- return; -+ i = 0; -+ while (entry && i < image) { -+ entry = entry->next; - -- line = getLineByType(LT_TITLE, entry->lines); -+ while (entry && entry->skip) -+ entry = entry->next; -+ i++; -+ } - -- if (line && line->numElements >= 2) -- fprintf(out, "%sdefault%s%s\n", indent, separator, -- line->elements[1].item); -- else if (line && (line->numElements == 1) && -- cfg->cfi->titleBracketed) { -- char *title = extractTitle(cfg, line); -- if (title) { -- fprintf(out, "%sdefault%s%s\n", indent, separator, title); -- free(title); -+ if (!entry) -+ return; -+ -+ line = getLineByType(LT_TITLE, entry->lines); -+ -+ if (line && line->numElements >= 2) -+ fprintf(out, "%sdefault%s%s\n", indent, -+ separator, line->elements[1].item); -+ else if (line && (line->numElements == 1) -+ && cfg->cfi->titleBracketed) { -+ char *title = extractTitle(cfg, line); -+ if (title) { -+ fprintf(out, "%sdefault%s%s\n", indent, -+ separator, title); -+ free(title); -+ } -+ } - } -- } - } -- } - } - --static int writeConfig(struct grubConfig * cfg, char * outName, -- const char * prefix) { -- FILE * out; -- struct singleLine * line; -- struct singleEntry * entry; -- char * tmpOutName; -- int needs = MAIN_DEFAULT; -- struct stat sb; -- int i; -- -- if (!strcmp(outName, "-")) { -- out = stdout; -- tmpOutName = NULL; -- } else { -- if (!lstat(outName, &sb) && S_ISLNK(sb.st_mode)) { -- char * buf; -- int len = 256; -- int rc; -- -- /* most likely the symlink is relative, so change our -- directory to the dir of the symlink */ -- char *dir = strdupa(outName); -- rc = chdir(dirname(dir)); -- do { -- buf = alloca(len + 1); -- rc = readlink(basename(outName), buf, len); -- if (rc == len) len += 256; -- } while (rc == len); -- -- if (rc < 0) { -- fprintf(stderr, _("grubby: error readlink link %s: %s\n"), -- outName, strerror(errno)); -- return 1; -- } -- -- outName = buf; -- outName[rc] = '\0'; -- } -- -- tmpOutName = alloca(strlen(outName) + 2); -- sprintf(tmpOutName, "%s-", outName); -- out = fopen(tmpOutName, "w"); -- if (!out) { -- fprintf(stderr, _("grubby: error creating %s: %s\n"), tmpOutName, -- strerror(errno)); -- return 1; -- } -- -- if (!stat(outName, &sb)) { -- if (chmod(tmpOutName, sb.st_mode & ~(S_IFMT))) { -- fprintf(stderr, _("grubby: error setting perms on %s: %s\n"), -- tmpOutName, strerror(errno)); -- fclose(out); -- unlink(tmpOutName); -- return 1; -- } -- } -- } -- -- line = cfg->theLines; -- struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi); -- while (line) { -- if (line->type == LT_SET_VARIABLE && defaultKw && -- line->numElements == 3 && -- !strcmp(line->elements[1].item, defaultKw->key) && -- !is_special_grub2_variable(line->elements[2].item)) { -- writeDefault(out, line->indent, line->elements[0].indent, cfg); -- needs &= ~MAIN_DEFAULT; -- } else if (line->type == LT_DEFAULT) { -- writeDefault(out, line->indent, line->elements[0].indent, cfg); -- needs &= ~MAIN_DEFAULT; -- } else if (line->type == LT_FALLBACK) { -- if (cfg->fallbackImage > -1) -- fprintf(out, "%s%s%s%d\n", line->indent, -- line->elements[0].item, line->elements[0].indent, -- cfg->fallbackImage); -+static int writeConfig(struct grubConfig *cfg, char *outName, -+ const char *prefix) -+{ -+ FILE *out; -+ struct singleLine *line; -+ struct singleEntry *entry; -+ char *tmpOutName; -+ int needs = MAIN_DEFAULT; -+ struct stat sb; -+ int i; -+ -+ if (!strcmp(outName, "-")) { -+ out = stdout; -+ tmpOutName = NULL; - } else { -- if (lineWrite(out, line, cfg->cfi) == -1) { -- fprintf(stderr, _("grubby: error writing %s: %s\n"), -- tmpOutName, strerror(errno)); -- fclose(out); -- unlink(tmpOutName); -- return 1; -- } -- } -+ if (!lstat(outName, &sb) && S_ISLNK(sb.st_mode)) { -+ char *buf; -+ int len = 256; -+ int rc; -+ -+ /* most likely the symlink is relative, so change our -+ directory to the dir of the symlink */ -+ char *dir = strdupa(outName); -+ rc = chdir(dirname(dir)); -+ do { -+ buf = alloca(len + 1); -+ rc = readlink(basename(outName), buf, len); -+ if (rc == len) -+ len += 256; -+ } while (rc == len); -+ -+ if (rc < 0) { -+ fprintf(stderr, -+ _ -+ ("grubby: error readlink link %s: %s\n"), -+ outName, strerror(errno)); -+ return 1; -+ } - -- line = line->next; -- } -+ outName = buf; -+ outName[rc] = '\0'; -+ } - -- if (needs & MAIN_DEFAULT) { -- writeDefault(out, cfg->primaryIndent, "=", cfg); -- needs &= ~MAIN_DEFAULT; -- } -+ tmpOutName = alloca(strlen(outName) + 2); -+ sprintf(tmpOutName, "%s-", outName); -+ out = fopen(tmpOutName, "w"); -+ if (!out) { -+ fprintf(stderr, _("grubby: error creating %s: %s\n"), -+ tmpOutName, strerror(errno)); -+ return 1; -+ } - -- i = 0; -- while ((entry = findEntryByIndex(cfg, i++))) { -- if (entry->skip) continue; -+ if (!stat(outName, &sb)) { -+ if (chmod(tmpOutName, sb.st_mode & ~(S_IFMT))) { -+ fprintf(stderr, -+ _ -+ ("grubby: error setting perms on %s: %s\n"), -+ tmpOutName, strerror(errno)); -+ fclose(out); -+ unlink(tmpOutName); -+ return 1; -+ } -+ } -+ } - -- line = entry->lines; -+ line = cfg->theLines; -+ struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi); - while (line) { -- if (lineWrite(out, line, cfg->cfi) == -1) { -- fprintf(stderr, _("grubby: error writing %s: %s\n"), -- tmpOutName, strerror(errno)); -- fclose(out); -- unlink(tmpOutName); -- return 1; -- } -- line = line->next; -- } -- } -- -- if (tmpOutName) { -- if (rename(tmpOutName, outName)) { -- fprintf(stderr, _("grubby: error moving %s to %s: %s\n"), -- tmpOutName, outName, strerror(errno)); -- unlink(outName); -- return 1; -- } -- } -- -- return 0; --} -- --static int numEntries(struct grubConfig *cfg) { -- int i = 0; -- struct singleEntry * entry; -- -- entry = cfg->entries; -- while (entry) { -- if (!entry->skip) -- i++; -- entry = entry->next; -- } -- return i; --} -+ if (line->type == LT_SET_VARIABLE && defaultKw && -+ line->numElements == 3 && -+ !strcmp(line->elements[1].item, defaultKw->key) && -+ !is_special_grub2_variable(line->elements[2].item)) { -+ writeDefault(out, line->indent, -+ line->elements[0].indent, cfg); -+ needs &= ~MAIN_DEFAULT; -+ } else if (line->type == LT_DEFAULT) { -+ writeDefault(out, line->indent, -+ line->elements[0].indent, cfg); -+ needs &= ~MAIN_DEFAULT; -+ } else if (line->type == LT_FALLBACK) { -+ if (cfg->fallbackImage > -1) -+ fprintf(out, "%s%s%s%d\n", line->indent, -+ line->elements[0].item, -+ line->elements[0].indent, -+ cfg->fallbackImage); -+ } else { -+ if (lineWrite(out, line, cfg->cfi) == -1) { -+ fprintf(stderr, -+ _("grubby: error writing %s: %s\n"), -+ tmpOutName, strerror(errno)); -+ fclose(out); -+ unlink(tmpOutName); -+ return 1; -+ } -+ } - --static char *findDiskForRoot() --{ -- int fd; -- char buf[65536]; -- char *devname; -- char *chptr; -- int rc; -- -- if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) { -- fprintf(stderr, "grubby: failed to open %s: %s\n", -- _PATH_MOUNTED, strerror(errno)); -- return NULL; -- } -- -- rc = read(fd, buf, sizeof(buf) - 1); -- if (rc <= 0) { -- fprintf(stderr, "grubby: failed to read %s: %s\n", -- _PATH_MOUNTED, strerror(errno)); -- close(fd); -- return NULL; -- } -- close(fd); -- buf[rc] = '\0'; -- chptr = buf; -- -- char *foundanswer = NULL; -- -- while (chptr && chptr != buf+rc) { -- devname = chptr; -- -- /* -- * The first column of a mtab entry is the device, but if the entry is a -- * special device it won't start with /, so move on to the next line. -- */ -- if (*devname != '/') { -- chptr = strchr(chptr, '\n'); -- if (chptr) -- chptr++; -- continue; -- } -- -- /* Seek to the next space */ -- chptr = strchr(chptr, ' '); -- if (!chptr) { -- fprintf(stderr, "grubby: error parsing %s: %s\n", -- _PATH_MOUNTED, strerror(errno)); -- return NULL; -- } -- -- /* -- * The second column of a mtab entry is the mount point, we are looking -- * for '/' obviously. -- */ -- if (*(++chptr) == '/' && *(++chptr) == ' ') { -- /* remember the last / entry in mtab */ -- foundanswer = devname; -- } -- -- /* Next line */ -- chptr = strchr(chptr, '\n'); -- if (chptr) -- chptr++; -- } -- -- /* Return the last / entry found */ -- if (foundanswer) { -- chptr = strchr(foundanswer, ' '); -- *chptr = '\0'; -- return strdup(foundanswer); -- } -- -- return NULL; --} -+ line = line->next; -+ } - --void printEntry(struct singleEntry * entry, FILE *f) { -- int i; -- struct singleLine * line; -+ if (needs & MAIN_DEFAULT) { -+ writeDefault(out, cfg->primaryIndent, "=", cfg); -+ needs &= ~MAIN_DEFAULT; -+ } - -- for (line = entry->lines; line; line = line->next) { -- log_message(f, "DBG: %s", line->indent); -- for (i = 0; i < line->numElements; i++) { -- /* Need to handle this, because we strip the quotes from -- * menuentry when read it. */ -- if (line->type == LT_MENUENTRY && i == 1) { -- if(!isquote(*line->elements[i].item)) -- log_message(f, "\'%s\'", line->elements[i].item); -- else -- log_message(f, "%s", line->elements[i].item); -- log_message(f, "%s", line->elements[i].indent); -- -- continue; -- } -- -- log_message(f, "%s%s", -- line->elements[i].item, line->elements[i].indent); -- } -- log_message(f, "\n"); -- } -+ i = 0; -+ while ((entry = findEntryByIndex(cfg, i++))) { -+ if (entry->skip) -+ continue; -+ -+ line = entry->lines; -+ while (line) { -+ if (lineWrite(out, line, cfg->cfi) == -1) { -+ fprintf(stderr, -+ _("grubby: error writing %s: %s\n"), -+ tmpOutName, strerror(errno)); -+ fclose(out); -+ unlink(tmpOutName); -+ return 1; -+ } -+ line = line->next; -+ } -+ } -+ -+ if (tmpOutName) { -+ if (rename(tmpOutName, outName)) { -+ fprintf(stderr, -+ _("grubby: error moving %s to %s: %s\n"), -+ tmpOutName, outName, strerror(errno)); -+ unlink(outName); -+ return 1; -+ } -+ } -+ -+ return 0; - } - --void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...) -+static int numEntries(struct grubConfig *cfg) - { -- static int once; -- va_list argp, argq; -- -- va_start(argp, fmt); -- -- va_copy(argq, argp); -- if (!once) { -- log_time(NULL); -- log_message(NULL, "command line: %s\n", saved_command_line); -- } -- log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed"); -- log_vmessage(NULL, fmt, argq); -- -- printEntry(entry, NULL); -- va_end(argq); -- -- if (!debug) { -- once = 1; -- va_end(argp); -- return; -- } -+ int i = 0; -+ struct singleEntry *entry; -+ -+ entry = cfg->entries; -+ while (entry) { -+ if (!entry->skip) -+ i++; -+ entry = entry->next; -+ } -+ return i; -+} -+ -+static char *findDiskForRoot() -+{ -+ int fd; -+ char buf[65536]; -+ char *devname; -+ char *chptr; -+ int rc; -+ -+ if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) { -+ fprintf(stderr, "grubby: failed to open %s: %s\n", -+ _PATH_MOUNTED, strerror(errno)); -+ return NULL; -+ } -+ -+ rc = read(fd, buf, sizeof(buf) - 1); -+ if (rc <= 0) { -+ fprintf(stderr, "grubby: failed to read %s: %s\n", -+ _PATH_MOUNTED, strerror(errno)); -+ close(fd); -+ return NULL; -+ } -+ close(fd); -+ buf[rc] = '\0'; -+ chptr = buf; -+ -+ char *foundanswer = NULL; -+ -+ while (chptr && chptr != buf + rc) { -+ devname = chptr; -+ -+ /* -+ * The first column of a mtab entry is the device, but if the entry is a -+ * special device it won't start with /, so move on to the next line. -+ */ -+ if (*devname != '/') { -+ chptr = strchr(chptr, '\n'); -+ if (chptr) -+ chptr++; -+ continue; -+ } -+ -+ /* Seek to the next space */ -+ chptr = strchr(chptr, ' '); -+ if (!chptr) { -+ fprintf(stderr, "grubby: error parsing %s: %s\n", -+ _PATH_MOUNTED, strerror(errno)); -+ return NULL; -+ } -+ -+ /* -+ * The second column of a mtab entry is the mount point, we are looking -+ * for '/' obviously. -+ */ -+ if (*(++chptr) == '/' && *(++chptr) == ' ') { -+ /* remember the last / entry in mtab */ -+ foundanswer = devname; -+ } -+ -+ /* Next line */ -+ chptr = strchr(chptr, '\n'); -+ if (chptr) -+ chptr++; -+ } -+ -+ /* Return the last / entry found */ -+ if (foundanswer) { -+ chptr = strchr(foundanswer, ' '); -+ *chptr = '\0'; -+ return strdup(foundanswer); -+ } -+ -+ return NULL; -+} -+ -+void printEntry(struct singleEntry *entry, FILE * f) -+{ -+ int i; -+ struct singleLine *line; -+ -+ for (line = entry->lines; line; line = line->next) { -+ log_message(f, "DBG: %s", line->indent); -+ for (i = 0; i < line->numElements; i++) { -+ /* Need to handle this, because we strip the quotes from -+ * menuentry when read it. */ -+ if (line->type == LT_MENUENTRY && i == 1) { -+ if (!isquote(*line->elements[i].item)) -+ log_message(f, "\'%s\'", -+ line->elements[i].item); -+ else -+ log_message(f, "%s", -+ line->elements[i].item); -+ log_message(f, "%s", line->elements[i].indent); -+ -+ continue; -+ } -+ -+ log_message(f, "%s%s", -+ line->elements[i].item, -+ line->elements[i].indent); -+ } -+ log_message(f, "\n"); -+ } -+} - -- if (okay) { -+void notSuitablePrintf(struct singleEntry *entry, int okay, const char *fmt, -+ ...) -+{ -+ static int once; -+ va_list argp, argq; -+ -+ va_start(argp, fmt); -+ -+ va_copy(argq, argp); -+ if (!once) { -+ log_time(NULL); -+ log_message(NULL, "command line: %s\n", saved_command_line); -+ } -+ log_message(NULL, "DBG: Image entry %s: ", -+ okay ? "succeeded" : "failed"); -+ log_vmessage(NULL, fmt, argq); -+ -+ printEntry(entry, NULL); -+ va_end(argq); -+ -+ if (!debug) { -+ once = 1; -+ va_end(argp); -+ return; -+ } -+ -+ if (okay) { -+ va_end(argp); -+ return; -+ } -+ -+ if (!once) -+ log_message(stderr, "DBG: command line: %s\n", -+ saved_command_line); -+ once = 1; -+ fprintf(stderr, "DBG: Image entry failed: "); -+ vfprintf(stderr, fmt, argp); -+ printEntry(entry, stderr); - va_end(argp); -- return; -- } -- -- if (!once) -- log_message(stderr, "DBG: command line: %s\n", saved_command_line); -- once = 1; -- fprintf(stderr, "DBG: Image entry failed: "); -- vfprintf(stderr, fmt, argp); -- printEntry(entry, stderr); -- va_end(argp); - } - - #define beginswith(s, c) ((s) && (s)[0] == (c)) -@@ -1860,281 +1979,317 @@ static int endswith(const char *s, char c) - return s[slen] == c; - } - --int suitableImage(struct singleEntry * entry, const char * bootPrefix, -- int skipRemoved, int flags) { -- struct singleLine * line; -- char * fullName; -- int i; -- char * dev; -- char * rootspec; -- char * rootdev; -- -- if (skipRemoved && entry->skip) { -- notSuitablePrintf(entry, 0, "marked to skip\n"); -- return 0; -- } -+int suitableImage(struct singleEntry *entry, const char *bootPrefix, -+ int skipRemoved, int flags) -+{ -+ struct singleLine *line; -+ char *fullName; -+ int i; -+ char *dev; -+ char *rootspec; -+ char *rootdev; -+ -+ if (skipRemoved && entry->skip) { -+ notSuitablePrintf(entry, 0, "marked to skip\n"); -+ return 0; -+ } - -- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); -- if (!line) { -- notSuitablePrintf(entry, 0, "no line found\n"); -- return 0; -- } -- if (line->numElements < 2) { -- notSuitablePrintf(entry, 0, "line has only %d elements\n", -- line->numElements); -- return 0; -- } -- -- if (flags & GRUBBY_BADIMAGE_OKAY) { -- notSuitablePrintf(entry, 1, "\n"); -- return 1; -- } -- -- fullName = alloca(strlen(bootPrefix) + -- strlen(line->elements[1].item) + 1); -- rootspec = getRootSpecifier(line->elements[1].item); -- int rootspec_offset = rootspec ? strlen(rootspec) : 0; -- int hasslash = endswith(bootPrefix, '/') || -- beginswith(line->elements[1].item + rootspec_offset, '/'); -- sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/", -- line->elements[1].item + rootspec_offset); -- if (access(fullName, R_OK)) { -- notSuitablePrintf(entry, 0, "access to %s failed\n", fullName); -- return 0; -- } -- for (i = 2; i < line->numElements; i++) -- if (!strncasecmp(line->elements[i].item, "root=", 5)) break; -- if (i < line->numElements) { -- dev = line->elements[i].item + 5; -- } else { -- /* look for a lilo style LT_ROOT line */ -- line = getLineByType(LT_ROOT, entry->lines); -+ line = -+ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | LT_KERNEL_16, -+ entry->lines); -+ if (!line) { -+ notSuitablePrintf(entry, 0, "no line found\n"); -+ return 0; -+ } -+ if (line->numElements < 2) { -+ notSuitablePrintf(entry, 0, "line has only %d elements\n", -+ line->numElements); -+ return 0; -+ } - -- if (line && line->numElements >= 2) { -- dev = line->elements[1].item; -- } else { -- /* 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. -- */ -- line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines); -+ if (flags & GRUBBY_BADIMAGE_OKAY) { -+ notSuitablePrintf(entry, 1, "\n"); -+ return 1; -+ } - -- /* failed to find one */ -- if (!line) { -- notSuitablePrintf(entry, 0, "no line found\n"); -+ fullName = alloca(strlen(bootPrefix) + -+ strlen(line->elements[1].item) + 1); -+ rootspec = getRootSpecifier(line->elements[1].item); -+ int rootspec_offset = rootspec ? strlen(rootspec) : 0; -+ int hasslash = endswith(bootPrefix, '/') || -+ beginswith(line->elements[1].item + rootspec_offset, '/'); -+ sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/", -+ line->elements[1].item + rootspec_offset); -+ if (access(fullName, R_OK)) { -+ notSuitablePrintf(entry, 0, "access to %s failed\n", fullName); - return 0; -- } -- -- for (i = 1; i < line->numElements; i++) -- if (!strncasecmp(line->elements[i].item, "root=", 5)) break; -- if (i < line->numElements) -- dev = line->elements[i].item + 5; -- else { -- notSuitablePrintf(entry, 0, "no root= entry found\n"); -- /* it failed too... can't find root= */ -- return 0; -- } -- } -- } -- -- dev = getpathbyspec(dev); -- if (!getpathbyspec(dev)) { -- notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev); -- return 0; -- } else -+ } -+ for (i = 2; i < line->numElements; i++) -+ if (!strncasecmp(line->elements[i].item, "root=", 5)) -+ break; -+ if (i < line->numElements) { -+ dev = line->elements[i].item + 5; -+ } else { -+ /* look for a lilo style LT_ROOT line */ -+ line = getLineByType(LT_ROOT, entry->lines); -+ -+ if (line && line->numElements >= 2) { -+ dev = line->elements[1].item; -+ } else { -+ /* 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. -+ */ -+ line = -+ getLineByType(LT_KERNELARGS | LT_MBMODULE, -+ entry->lines); -+ -+ /* failed to find one */ -+ if (!line) { -+ notSuitablePrintf(entry, 0, "no line found\n"); -+ return 0; -+ } -+ -+ for (i = 1; i < line->numElements; i++) -+ if (!strncasecmp -+ (line->elements[i].item, "root=", 5)) -+ break; -+ if (i < line->numElements) -+ dev = line->elements[i].item + 5; -+ else { -+ notSuitablePrintf(entry, 0, -+ "no root= entry found\n"); -+ /* it failed too... can't find root= */ -+ return 0; -+ } -+ } -+ } -+ - dev = getpathbyspec(dev); -+ if (!getpathbyspec(dev)) { -+ notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", -+ dev); -+ return 0; -+ } else -+ dev = getpathbyspec(dev); - -- rootdev = findDiskForRoot(); -- if (!rootdev) { -- notSuitablePrintf(entry, 0, "can't find root device\n"); -- return 0; -- } -- -- if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) { -- notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n", -- getuuidbydev(rootdev), getuuidbydev(dev)); -- free(rootdev); -- return 0; -- } -- -- if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { -- notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n", -- getuuidbydev(rootdev), getuuidbydev(dev)); -- free(rootdev); -- return 0; -- } -+ rootdev = findDiskForRoot(); -+ if (!rootdev) { -+ notSuitablePrintf(entry, 0, "can't find root device\n"); -+ return 0; -+ } - -- free(rootdev); -- notSuitablePrintf(entry, 1, "\n"); -+ if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) { -+ notSuitablePrintf(entry, 0, -+ "uuid missing: rootdev %s, dev %s\n", -+ getuuidbydev(rootdev), getuuidbydev(dev)); -+ free(rootdev); -+ return 0; -+ } -+ -+ if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { -+ notSuitablePrintf(entry, 0, -+ "uuid mismatch: rootdev %s, dev %s\n", -+ getuuidbydev(rootdev), getuuidbydev(dev)); -+ free(rootdev); -+ return 0; -+ } -+ -+ free(rootdev); -+ notSuitablePrintf(entry, 1, "\n"); - -- return 1; -+ return 1; - } - - /* returns the first match on or after the one pointed to by index (if index - is not NULL) which is not marked as skip */ --struct singleEntry * findEntryByPath(struct grubConfig * config, -- const char * kernel, const char * prefix, -- int * index) { -- struct singleEntry * entry = NULL; -- struct singleLine * line; -- int i; -- char * chptr; -- char * rootspec = NULL; -- enum lineType_e checkType = LT_KERNEL; -- -- if (isdigit(*kernel)) { -- int * indexVars = alloca(sizeof(*indexVars) * strlen(kernel)); -- -- i = 0; -- indexVars[i] = strtol(kernel, &chptr, 10); -- while (*chptr == ',') { -- i++; -- kernel = chptr + 1; -- indexVars[i] = strtol(kernel, &chptr, 10); -- } -+struct singleEntry *findEntryByPath(struct grubConfig *config, -+ const char *kernel, const char *prefix, -+ int *index) -+{ -+ struct singleEntry *entry = NULL; -+ struct singleLine *line; -+ int i; -+ char *chptr; -+ char *rootspec = NULL; -+ enum lineType_e checkType = LT_KERNEL; -+ -+ if (isdigit(*kernel)) { -+ int *indexVars = alloca(sizeof(*indexVars) * strlen(kernel)); -+ -+ i = 0; -+ indexVars[i] = strtol(kernel, &chptr, 10); -+ while (*chptr == ',') { -+ i++; -+ kernel = chptr + 1; -+ indexVars[i] = strtol(kernel, &chptr, 10); -+ } - -- if (*chptr) { -- /* can't parse it, bail */ -- return NULL; -- } -+ if (*chptr) { -+ /* can't parse it, bail */ -+ return NULL; -+ } - -- indexVars[i + 1] = -1; -+ indexVars[i + 1] = -1; - -- i = 0; -- if (index) { -- while (i < *index) { -- i++; -- if (indexVars[i] == -1) return NULL; -- } -- } -+ i = 0; -+ if (index) { -+ while (i < *index) { -+ i++; -+ if (indexVars[i] == -1) -+ return NULL; -+ } -+ } - -- entry = findEntryByIndex(config, indexVars[i]); -- if (!entry) return NULL; -+ entry = findEntryByIndex(config, indexVars[i]); -+ if (!entry) -+ return NULL; - -- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); -- if (!line) return NULL; -+ line = -+ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | -+ LT_KERNEL_16, entry->lines); -+ if (!line) -+ return NULL; - -- if (index) *index = indexVars[i]; -- return entry; -- } -- -- if (!strcmp(kernel, "DEFAULT")) { -- if (index && *index > config->defaultImage) { -- entry = NULL; -- } else { -- entry = findEntryByIndex(config, config->defaultImage); -- if (entry && entry->skip) -- entry = NULL; -- else if (index) -- *index = config->defaultImage; -+ if (index) -+ *index = indexVars[i]; -+ return entry; - } -- } else if (!strcmp(kernel, "ALL")) { -- if (index) -- i = *index; -- else -- i = 0; - -- while ((entry = findEntryByIndex(config, i))) { -- if (!entry->skip) break; -- i++; -- } -+ if (!strcmp(kernel, "DEFAULT")) { -+ if (index && *index > config->defaultImage) { -+ entry = NULL; -+ } else { -+ entry = findEntryByIndex(config, config->defaultImage); -+ if (entry && entry->skip) -+ entry = NULL; -+ else if (index) -+ *index = config->defaultImage; -+ } -+ } else if (!strcmp(kernel, "ALL")) { -+ if (index) -+ i = *index; -+ else -+ i = 0; - -- if (entry && index) -- *index = i; -- } else { -- if (index) -- i = *index; -- else -- i = 0; -+ while ((entry = findEntryByIndex(config, i))) { -+ if (!entry->skip) -+ break; -+ i++; -+ } - -- if (!strncmp(kernel, "TITLE=", 6)) { -- prefix = ""; -- checkType = LT_TITLE|LT_MENUENTRY; -- kernel += 6; -- } -+ if (entry && index) -+ *index = i; -+ } else { -+ if (index) -+ i = *index; -+ else -+ i = 0; - -- for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) { -- if (entry->skip) continue; -+ if (!strncmp(kernel, "TITLE=", 6)) { -+ prefix = ""; -+ checkType = LT_TITLE | LT_MENUENTRY; -+ kernel += 6; -+ } - -- dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry); -+ for (entry = findEntryByIndex(config, i); entry; -+ entry = entry->next, i++) { -+ if (entry->skip) -+ continue; -+ -+ dbgPrintf("findEntryByPath looking for %d %s in %p\n", -+ checkType, kernel, entry); -+ -+ /* check all the lines matching checkType */ -+ for (line = entry->lines; line; line = line->next) { -+ enum lineType_e ct = checkType; -+ if (entry->multiboot && checkType == LT_KERNEL) -+ ct = LT_KERNEL | LT_KERNEL_EFI | -+ LT_MBMODULE | LT_HYPER | -+ LT_KERNEL_16; -+ else if (checkType & LT_KERNEL) -+ ct = checkType | LT_KERNEL_EFI | -+ LT_KERNEL_16; -+ line = getLineByType(ct, line); -+ if (!line) -+ break; /* not found in this entry */ -+ -+ if (line && line->type != LT_MENUENTRY && -+ line->numElements >= 2) { -+ rootspec = -+ getRootSpecifier(line->elements[1]. -+ item); -+ if (!strcmp -+ (line->elements[1].item + -+ ((rootspec != -+ NULL) ? strlen(rootspec) : 0), -+ kernel + strlen(prefix))) -+ break; -+ } -+ if (line->type == LT_MENUENTRY && -+ !strcmp(line->elements[1].item, kernel)) -+ break; -+ } - -- /* check all the lines matching checkType */ -- for (line = entry->lines; line; line = line->next) { -- enum lineType_e ct = checkType; -- if (entry->multiboot && checkType == LT_KERNEL) -- ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16; -- else if (checkType & LT_KERNEL) -- ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16; -- line = getLineByType(ct, line); -- if (!line) -- break; /* not found in this entry */ -- -- if (line && line->type != LT_MENUENTRY && -- line->numElements >= 2) { -- rootspec = getRootSpecifier(line->elements[1].item); -- if (!strcmp(line->elements[1].item + -- ((rootspec != NULL) ? strlen(rootspec) : 0), -- kernel + strlen(prefix))) -- break; -+ /* make sure this entry has a kernel identifier; this skips -+ * non-Linux boot entries (could find netbsd etc, though, which is -+ * unfortunate) -+ */ -+ if (line -+ && getLineByType(LT_KERNEL | LT_HYPER | -+ LT_KERNEL_EFI | LT_KERNEL_16, -+ entry->lines)) -+ break; /* found 'im! */ - } -- if(line->type == LT_MENUENTRY && -- !strcmp(line->elements[1].item, kernel)) -- break; -- } - -- /* make sure this entry has a kernel identifier; this skips -- * non-Linux boot entries (could find netbsd etc, though, which is -- * unfortunate) -- */ -- if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines)) -- break; /* found 'im! */ -+ if (index) -+ *index = i; - } - -- if (index) *index = i; -- } -- -- return entry; -+ return entry; - } - --struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title, -- int * index) { -- struct singleEntry * entry; -- struct singleLine * line; -- int i; -- char * newtitle; -+struct singleEntry *findEntryByTitle(struct grubConfig *cfg, char *title, -+ int *index) -+{ -+ struct singleEntry *entry; -+ struct singleLine *line; -+ int i; -+ char *newtitle; -+ -+ for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) { -+ if (index && i < *index) -+ continue; -+ line = getLineByType(LT_TITLE, entry->lines); -+ if (!line) -+ line = getLineByType(LT_MENUENTRY, entry->lines); -+ if (!line) -+ continue; -+ newtitle = grub2ExtractTitle(line); -+ if (!newtitle) -+ continue; -+ if (!strcmp(title, newtitle)) -+ break; -+ } - -- for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) { -- if (index && i < *index) -- continue; -- line = getLineByType(LT_TITLE, entry->lines); -- if (!line) -- line = getLineByType(LT_MENUENTRY, entry->lines); -- if (!line) -- continue; -- newtitle = grub2ExtractTitle(line); -- if (!newtitle) -- continue; -- if (!strcmp(title, newtitle)) -- break; -- } -- -- if (!entry) -- return NULL; -+ if (!entry) -+ return NULL; - -- if (index) -- *index = i; -- return entry; -+ if (index) -+ *index = i; -+ return entry; - } - --struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) { -- struct singleEntry * entry; -+struct singleEntry *findEntryByIndex(struct grubConfig *cfg, int index) -+{ -+ struct singleEntry *entry; - -- entry = cfg->entries; -- while (index && entry) { -- entry = entry->next; -- index--; -- } -+ entry = cfg->entries; -+ while (index && entry) { -+ entry = entry->next; -+ index--; -+ } - -- return entry; -+ return entry; - } - - /* Find a good template to use for the new kernel. An entry is -@@ -2142,2550 +2297,2822 @@ struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) { - * is going to be removed). Try and use the default entry, but - * if that doesn't work just take the first. If we can't find one, - * bail. */ --struct singleEntry * findTemplate(struct grubConfig * cfg, const char * prefix, -- int * indexPtr, int skipRemoved, int flags) { -- struct singleEntry * entry, * entry2; -- int index; -- -- if (cfg->cfi->defaultIsSaved) { -- if (cfg->cfi->getEnv) { -- char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry"); -- if (defTitle) { -- int index = 0; -- if (isnumber(defTitle)) { -- index = atoi(defTitle); -- entry = findEntryByIndex(cfg, index); -- } else { -- entry = findEntryByTitle(cfg, defTitle, &index); -+struct singleEntry *findTemplate(struct grubConfig *cfg, const char *prefix, -+ int *indexPtr, int skipRemoved, int flags) -+{ -+ struct singleEntry *entry, *entry2; -+ int index; -+ -+ if (cfg->cfi->defaultIsSaved) { -+ if (cfg->cfi->getEnv) { -+ char *defTitle = -+ cfg->cfi->getEnv(cfg->cfi, "saved_entry"); -+ if (defTitle) { -+ int index = 0; -+ if (isnumber(defTitle)) { -+ index = atoi(defTitle); -+ entry = findEntryByIndex(cfg, index); -+ } else { -+ entry = -+ findEntryByTitle(cfg, defTitle, -+ &index); -+ } -+ if (entry -+ && suitableImage(entry, prefix, skipRemoved, -+ flags)) { -+ cfg->defaultImage = index; -+ if (indexPtr) -+ *indexPtr = index; -+ return entry; -+ } -+ } - } -+ } else if (cfg->defaultImage > -1) { -+ entry = findEntryByIndex(cfg, cfg->defaultImage); - if (entry && suitableImage(entry, prefix, skipRemoved, flags)) { -- cfg->defaultImage = index; -- if (indexPtr) -- *indexPtr = index; -- return entry; -+ if (indexPtr) -+ *indexPtr = cfg->defaultImage; -+ return entry; - } -- } - } -- } else if (cfg->defaultImage > -1) { -- entry = findEntryByIndex(cfg, cfg->defaultImage); -- if (entry && suitableImage(entry, prefix, skipRemoved, flags)) { -- if (indexPtr) *indexPtr = cfg->defaultImage; -- return entry; -- } -- } - -- index = 0; -- while ((entry = findEntryByIndex(cfg, index))) { -- if (suitableImage(entry, prefix, skipRemoved, flags)) { -- int j; -- for (j = 0; j < index; j++) { -- entry2 = findEntryByIndex(cfg, j); -- if (entry2->skip) index--; -- } -- if (indexPtr) *indexPtr = index; -+ index = 0; -+ while ((entry = findEntryByIndex(cfg, index))) { -+ if (suitableImage(entry, prefix, skipRemoved, flags)) { -+ int j; -+ for (j = 0; j < index; j++) { -+ entry2 = findEntryByIndex(cfg, j); -+ if (entry2->skip) -+ index--; -+ } -+ if (indexPtr) -+ *indexPtr = index; - -- return entry; -- } -+ return entry; -+ } - -- index++; -- } -+ index++; -+ } - -- fprintf(stderr, _("grubby fatal error: unable to find a suitable template\n")); -+ fprintf(stderr, -+ _("grubby fatal error: unable to find a suitable template\n")); - -- return NULL; -+ return NULL; - } - --char * findBootPrefix(void) { -- struct stat sb, sb2; -+char *findBootPrefix(void) -+{ -+ struct stat sb, sb2; - -- stat("/", &sb); -+ stat("/", &sb); - #ifdef __ia64__ -- stat("/boot/efi/EFI/redhat/", &sb2); -+ stat("/boot/efi/EFI/redhat/", &sb2); - #else -- stat("/boot", &sb2); -+ stat("/boot", &sb2); - #endif - -- if (sb.st_dev == sb2.st_dev) -- return strdup(""); -+ if (sb.st_dev == sb2.st_dev) -+ return strdup(""); - - #ifdef __ia64__ -- return strdup("/boot/efi/EFI/redhat/"); -+ return strdup("/boot/efi/EFI/redhat/"); - #else -- return strdup("/boot"); -+ return strdup("/boot"); - #endif - } - --void markRemovedImage(struct grubConfig * cfg, const char * image, -- const char * prefix) { -- struct singleEntry * entry; -+void markRemovedImage(struct grubConfig *cfg, const char *image, -+ const char *prefix) -+{ -+ struct singleEntry *entry; - -- if (!image) -- return; -+ if (!image) -+ return; - -- /* check and see if we're removing the default image */ -- if (isdigit(*image)) { -- entry = findEntryByPath(cfg, image, prefix, NULL); -- if(entry) -- entry->skip = 1; -- return; -- } -+ /* check and see if we're removing the default image */ -+ if (isdigit(*image)) { -+ entry = findEntryByPath(cfg, image, prefix, NULL); -+ if (entry) -+ entry->skip = 1; -+ return; -+ } - -- while ((entry = findEntryByPath(cfg, image, prefix, NULL))) -- entry->skip = 1; -+ while ((entry = findEntryByPath(cfg, image, prefix, NULL))) -+ entry->skip = 1; - } - --void setDefaultImage(struct grubConfig * config, int hasNew, -- const char * defaultKernelPath, int newIsDefault, -- const char * prefix, int flags, int index) { -- struct singleEntry * entry, * entry2, * newDefault; -- int i, j; -- -- if (newIsDefault) { -- config->defaultImage = 0; -- return; -- } else if ((index >= 0) && config->cfi->defaultIsIndex) { -- if (findEntryByIndex(config, index)) -- config->defaultImage = index; -- else -- config->defaultImage = -1; -- return; -- } else if (defaultKernelPath) { -- i = 0; -- if (findEntryByPath(config, defaultKernelPath, prefix, &i)) { -- config->defaultImage = i; -- } else { -- config->defaultImage = -1; -- return; -+void setDefaultImage(struct grubConfig *config, int hasNew, -+ const char *defaultKernelPath, int newIsDefault, -+ const char *prefix, int flags, int index) -+{ -+ struct singleEntry *entry, *entry2, *newDefault; -+ int i, j; -+ -+ if (newIsDefault) { -+ config->defaultImage = 0; -+ return; -+ } else if ((index >= 0) && config->cfi->defaultIsIndex) { -+ if (findEntryByIndex(config, index)) -+ config->defaultImage = index; -+ else -+ config->defaultImage = -1; -+ return; -+ } else if (defaultKernelPath) { -+ i = 0; -+ if (findEntryByPath(config, defaultKernelPath, prefix, &i)) { -+ config->defaultImage = i; -+ } else { -+ config->defaultImage = -1; -+ return; -+ } - } -- } - -- /* defaultImage now points to what we'd like to use, but before any order -- changes */ -- if ((config->defaultImage == DEFAULT_SAVED) || -- (config->defaultImage == DEFAULT_SAVED_GRUB2)) -- /* default is set to saved, we don't want to change it */ -- return; -+ /* defaultImage now points to what we'd like to use, but before any order -+ changes */ -+ if ((config->defaultImage == DEFAULT_SAVED) || -+ (config->defaultImage == DEFAULT_SAVED_GRUB2)) -+ /* default is set to saved, we don't want to change it */ -+ return; - -- if (config->defaultImage > -1) -- entry = findEntryByIndex(config, config->defaultImage); -- else -- entry = NULL; -+ if (config->defaultImage > -1) -+ entry = findEntryByIndex(config, config->defaultImage); -+ else -+ entry = NULL; - -- if (entry && !entry->skip) { -- /* we can preserve the default */ -- if (hasNew) -- config->defaultImage++; -- -- /* count the number of entries erased before this one */ -- for (j = 0; j < config->defaultImage; j++) { -- entry2 = findEntryByIndex(config, j); -- if (entry2->skip) config->defaultImage--; -- } -- } else if (hasNew) { -- config->defaultImage = 0; -- } else { -- /* Either we just erased the default (or the default line was bad -- * to begin with) and didn't put a new one in. We'll use the first -- * valid image. */ -- newDefault = findTemplate(config, prefix, &config->defaultImage, 1, -- flags); -- if (!newDefault) -- config->defaultImage = -1; -- } --} -+ if (entry && !entry->skip) { -+ /* we can preserve the default */ -+ if (hasNew) -+ config->defaultImage++; - --void setFallbackImage(struct grubConfig * config, int hasNew) { -- struct singleEntry * entry, * entry2; -- int j; -- -- if (config->fallbackImage == -1) return; -- -- entry = findEntryByIndex(config, config->fallbackImage); -- if (!entry || entry->skip) { -- config->fallbackImage = -1; -- return; -- } -- -- if (hasNew) -- config->fallbackImage++; -- -- /* count the number of entries erased before this one */ -- for (j = 0; j < config->fallbackImage; j++) { -- entry2 = findEntryByIndex(config, j); -- if (entry2->skip) config->fallbackImage--; -- } -+ /* count the number of entries erased before this one */ -+ for (j = 0; j < config->defaultImage; j++) { -+ entry2 = findEntryByIndex(config, j); -+ if (entry2->skip) -+ config->defaultImage--; -+ } -+ } else if (hasNew) { -+ config->defaultImage = 0; -+ } else { -+ /* Either we just erased the default (or the default line was bad -+ * to begin with) and didn't put a new one in. We'll use the first -+ * valid image. */ -+ newDefault = -+ findTemplate(config, prefix, &config->defaultImage, 1, -+ flags); -+ if (!newDefault) -+ config->defaultImage = -1; -+ } - } - --void displayEntry(struct singleEntry * entry, const char * prefix, int index) { -- struct singleLine * line; -- char * root = NULL; -- int i; -- -- printf("index=%d\n", index); -- -- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); -- if (!line) { -- printf("non linux entry\n"); -- return; -- } -- -- if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) -- printf("kernel=%s\n", line->elements[1].item); -- else -- printf("kernel=%s%s\n", prefix, line->elements[1].item); -- -- if (line->numElements >= 3) { -- printf("args=\""); -- i = 2; -- while (i < line->numElements) { -- if (!strncmp(line->elements[i].item, "root=", 5)) { -- root = line->elements[i].item + 5; -- } else { -- printf("%s%s", line->elements[i].item, -- line->elements[i].indent); -- } -- -- i++; -- } -- printf("\"\n"); -- } else { -- line = getLineByType(LT_KERNELARGS, entry->lines); -- if (line) { -- char * s; -+void setFallbackImage(struct grubConfig *config, int hasNew) -+{ -+ struct singleEntry *entry, *entry2; -+ int j; - -- printf("args=\""); -- i = 1; -- while (i < line->numElements) { -- if (!strncmp(line->elements[i].item, "root=", 5)) { -- root = line->elements[i].item + 5; -- } else { -- s = line->elements[i].item; -+ if (config->fallbackImage == -1) -+ return; - -- printf("%s%s", s, line->elements[i].indent); -- } -+ entry = findEntryByIndex(config, config->fallbackImage); -+ if (!entry || entry->skip) { -+ config->fallbackImage = -1; -+ return; -+ } - -- i++; -- } -+ if (hasNew) -+ config->fallbackImage++; - -- s = line->elements[i - 1].indent; -- printf("\"\n"); -+ /* count the number of entries erased before this one */ -+ for (j = 0; j < config->fallbackImage; j++) { -+ entry2 = findEntryByIndex(config, j); -+ if (entry2->skip) -+ config->fallbackImage--; - } -- } -+} - -- if (!root) { -- line = getLineByType(LT_ROOT, entry->lines); -- if (line && line->numElements >= 2) -- root=line->elements[1].item; -- } -+void displayEntry(struct singleEntry *entry, const char *prefix, int index) -+{ -+ struct singleLine *line; -+ char *root = NULL; -+ int i; - -- if (root) { -- char * s = alloca(strlen(root) + 1); -- -- strcpy(s, root); -- if (s[strlen(s) - 1] == '"') -- s[strlen(s) - 1] = '\0'; -- /* make sure the root doesn't have a trailing " */ -- printf("root=%s\n", s); -- } -+ printf("index=%d\n", index); - -- line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines); -+ line = -+ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | LT_KERNEL_16, -+ entry->lines); -+ if (!line) { -+ printf("non linux entry\n"); -+ return; -+ } - -- if (line && line->numElements >= 2) { - if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) -- printf("initrd="); -+ printf("kernel=%s\n", line->elements[1].item); - else -- printf("initrd=%s", prefix); -- -- for (i = 1; i < line->numElements; i++) -- printf("%s%s", line->elements[i].item, line->elements[i].indent); -- printf("\n"); -- } -- -- line = getLineByType(LT_TITLE, entry->lines); -- if (line) { -- printf("title=%s\n", line->elements[1].item); -- } else { -- char * title; -- line = getLineByType(LT_MENUENTRY, entry->lines); -- if (line) { -- title = grub2ExtractTitle(line); -- if (title) -- printf("title=%s\n", title); -- } -- } --} -- --int isSuseSystem(void) { -- const char * path; -- const static char default_path[] = "/etc/SuSE-release"; -- -- if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL) -- path = default_path; -- -- if (!access(path, R_OK)) -- return 1; -- return 0; --} -+ printf("kernel=%s%s\n", prefix, line->elements[1].item); -+ -+ if (line->numElements >= 3) { -+ printf("args=\""); -+ i = 2; -+ while (i < line->numElements) { -+ if (!strncmp(line->elements[i].item, "root=", 5)) { -+ root = line->elements[i].item + 5; -+ } else { -+ printf("%s%s", line->elements[i].item, -+ line->elements[i].indent); -+ } - --int isSuseGrubConf(const char * path) { -- FILE * grubConf; -- char * line = NULL; -- size_t len = 0, res = 0; -+ i++; -+ } -+ printf("\"\n"); -+ } else { -+ line = getLineByType(LT_KERNELARGS, entry->lines); -+ if (line) { -+ char *s; -+ -+ printf("args=\""); -+ i = 1; -+ while (i < line->numElements) { -+ if (!strncmp -+ (line->elements[i].item, "root=", 5)) { -+ root = line->elements[i].item + 5; -+ } else { -+ s = line->elements[i].item; -+ -+ printf("%s%s", s, -+ line->elements[i].indent); -+ } - -- grubConf = fopen(path, "r"); -- if (!grubConf) { -- dbgPrintf("Could not open SuSE configuration file '%s'\n", path); -- return 0; -- } -+ i++; -+ } - -- while ((res = getline(&line, &len, grubConf)) != -1) { -- if (!strncmp(line, "setup", 5)) { -- fclose(grubConf); -- free(line); -- return 1; -+ s = line->elements[i - 1].indent; -+ printf("\"\n"); -+ } - } -- } - -- dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n", -- path); -+ if (!root) { -+ line = getLineByType(LT_ROOT, entry->lines); -+ if (line && line->numElements >= 2) -+ root = line->elements[1].item; -+ } - -- fclose(grubConf); -- free(line); -- return 0; --} -+ if (root) { -+ char *s = alloca(strlen(root) + 1); - --int suseGrubConfGetLba(const char * path, int * lbaPtr) { -- FILE * grubConf; -- char * line = NULL; -- size_t res = 0, len = 0; -+ strcpy(s, root); -+ if (s[strlen(s) - 1] == '"') -+ s[strlen(s) - 1] = '\0'; -+ /* make sure the root doesn't have a trailing " */ -+ printf("root=%s\n", s); -+ } - -- if (!path) return 1; -- if (!lbaPtr) return 1; -+ line = -+ getLineByType(LT_INITRD | LT_INITRD_EFI | LT_INITRD_16, -+ entry->lines); - -- grubConf = fopen(path, "r"); -- if (!grubConf) return 1; -+ if (line && line->numElements >= 2) { -+ if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) -+ printf("initrd="); -+ else -+ printf("initrd=%s", prefix); - -- while ((res = getline(&line, &len, grubConf)) != -1) { -- if (line[res - 1] == '\n') -- line[res - 1] = '\0'; -- else if (len > res) -- line[res] = '\0'; -- else { -- line = realloc(line, res + 1); -- line[res] = '\0'; -+ for (i = 1; i < line->numElements; i++) -+ printf("%s%s", line->elements[i].item, -+ line->elements[i].indent); -+ printf("\n"); - } - -- if (!strncmp(line, "setup", 5)) { -- if (strstr(line, "--force-lba")) { -- *lbaPtr = 1; -- } else { -- *lbaPtr = 0; -- } -- dbgPrintf("lba: %i\n", *lbaPtr); -- break; -+ line = getLineByType(LT_TITLE, entry->lines); -+ if (line) { -+ printf("title=%s\n", line->elements[1].item); -+ } else { -+ char *title; -+ line = getLineByType(LT_MENUENTRY, entry->lines); -+ if (line) { -+ title = grub2ExtractTitle(line); -+ if (title) -+ printf("title=%s\n", title); -+ } - } -- } -- -- free(line); -- fclose(grubConf); -- return 0; - } - --int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) { -- FILE * grubConf; -- char * line = NULL; -- size_t res = 0, len = 0; -- char * lastParamPtr = NULL; -- char * secLastParamPtr = NULL; -- char installDeviceNumber = '\0'; -- char * bounds = NULL; -- -- if (!path) return 1; -- if (!devicePtr) return 1; -- -- grubConf = fopen(path, "r"); -- if (!grubConf) return 1; -- -- while ((res = getline(&line, &len, grubConf)) != -1) { -- if (strncmp(line, "setup", 5)) -- continue; -- -- if (line[res - 1] == '\n') -- line[res - 1] = '\0'; -- else if (len > res) -- line[res] = '\0'; -- else { -- line = realloc(line, res + 1); -- line[res] = '\0'; -- } -- -- lastParamPtr = bounds = line + res; -+int isSuseSystem(void) -+{ -+ const char *path; -+ const static char default_path[] = "/etc/SuSE-release"; - -- /* Last parameter in grub may be an optional IMAGE_DEVICE */ -- while (!isspace(*lastParamPtr)) -- lastParamPtr--; -- lastParamPtr++; -+ if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL) -+ path = default_path; - -- secLastParamPtr = lastParamPtr - 2; -- dbgPrintf("lastParamPtr: %s\n", lastParamPtr); -+ if (!access(path, R_OK)) -+ return 1; -+ return 0; -+} - -- if (lastParamPtr + 3 > bounds) { -- dbgPrintf("lastParamPtr going over boundary"); -- fclose(grubConf); -- free(line); -- return 1; -+int isSuseGrubConf(const char *path) -+{ -+ FILE *grubConf; -+ char *line = NULL; -+ size_t len = 0, res = 0; -+ -+ grubConf = fopen(path, "r"); -+ if (!grubConf) { -+ dbgPrintf("Could not open SuSE configuration file '%s'\n", -+ path); -+ return 0; - } -- if (!strncmp(lastParamPtr, "(hd", 3)) -- lastParamPtr += 3; -- dbgPrintf("lastParamPtr: %c\n", *lastParamPtr); - -- /* -- * Second last parameter will decide wether last parameter is -- * an IMAGE_DEVICE or INSTALL_DEVICE -- */ -- while (!isspace(*secLastParamPtr)) -- secLastParamPtr--; -- secLastParamPtr++; -- -- if (secLastParamPtr + 3 > bounds) { -- dbgPrintf("secLastParamPtr going over boundary"); -- fclose(grubConf); -- free(line); -- return 1; -- } -- dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr); -- if (!strncmp(secLastParamPtr, "(hd", 3)) { -- secLastParamPtr += 3; -- dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr); -- installDeviceNumber = *secLastParamPtr; -- } else { -- installDeviceNumber = *lastParamPtr; -+ while ((res = getline(&line, &len, grubConf)) != -1) { -+ if (!strncmp(line, "setup", 5)) { -+ fclose(grubConf); -+ free(line); -+ return 1; -+ } - } - -- *devicePtr = malloc(6); -- snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber); -- dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber); -+ dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n", -+ path); -+ - fclose(grubConf); - free(line); - return 0; -- } -- -- free(line); -- fclose(grubConf); -- return 1; - } - --int grubGetBootFromDeviceMap(const char * device, -- char ** bootPtr) { -- FILE * deviceMap; -- char * line = NULL; -- size_t res = 0, len = 0; -- char * devicePtr; -- char * bounds = NULL; -- const char * path; -- const static char default_path[] = "/boot/grub/device.map"; -- -- if (!device) return 1; -- if (!bootPtr) return 1; -- -- if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL) -- path = default_path; -- -- dbgPrintf("opening grub device.map file from: %s\n", path); -- deviceMap = fopen(path, "r"); -- if (!deviceMap) -- return 1; -- -- while ((res = getline(&line, &len, deviceMap)) != -1) { -- if (!strncmp(line, "#", 1)) -- continue; -- -- if (line[res - 1] == '\n') -- line[res - 1] = '\0'; -- else if (len > res) -- line[res] = '\0'; -- else { -- line = realloc(line, res + 1); -- line[res] = '\0'; -- } -+int suseGrubConfGetLba(const char *path, int *lbaPtr) -+{ -+ FILE *grubConf; -+ char *line = NULL; -+ size_t res = 0, len = 0; - -- devicePtr = line; -- bounds = line + res; -+ if (!path) -+ return 1; -+ if (!lbaPtr) -+ return 1; - -- while ((isspace(*line) && ((devicePtr + 1) <= bounds))) -- devicePtr++; -- dbgPrintf("device: %s\n", devicePtr); -+ grubConf = fopen(path, "r"); -+ if (!grubConf) -+ return 1; - -- if (!strncmp(devicePtr, device, strlen(device))) { -- devicePtr += strlen(device); -- while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds)) -- devicePtr++; -+ while ((res = getline(&line, &len, grubConf)) != -1) { -+ if (line[res - 1] == '\n') -+ line[res - 1] = '\0'; -+ else if (len > res) -+ line[res] = '\0'; -+ else { -+ line = realloc(line, res + 1); -+ line[res] = '\0'; -+ } - -- *bootPtr = strdup(devicePtr); -- break; -+ if (!strncmp(line, "setup", 5)) { -+ if (strstr(line, "--force-lba")) { -+ *lbaPtr = 1; -+ } else { -+ *lbaPtr = 0; -+ } -+ dbgPrintf("lba: %i\n", *lbaPtr); -+ break; -+ } - } -- } - -- free(line); -- fclose(deviceMap); -- return 0; -+ free(line); -+ fclose(grubConf); -+ return 0; - } - --int suseGrubConfGetBoot(const char * path, char ** bootPtr) { -- char * grubDevice; -+int suseGrubConfGetInstallDevice(const char *path, char **devicePtr) -+{ -+ FILE *grubConf; -+ char *line = NULL; -+ size_t res = 0, len = 0; -+ char *lastParamPtr = NULL; -+ char *secLastParamPtr = NULL; -+ char installDeviceNumber = '\0'; -+ char *bounds = NULL; -+ -+ if (!path) -+ return 1; -+ if (!devicePtr) -+ return 1; - -- if (suseGrubConfGetInstallDevice(path, &grubDevice)) -- dbgPrintf("error looking for grub installation device\n"); -- else -- dbgPrintf("grubby installation device: %s\n", grubDevice); -+ grubConf = fopen(path, "r"); -+ if (!grubConf) -+ return 1; - -- if (grubGetBootFromDeviceMap(grubDevice, bootPtr)) -- dbgPrintf("error looking for grub boot device\n"); -- else -- dbgPrintf("grubby boot device: %s\n", *bootPtr); -+ while ((res = getline(&line, &len, grubConf)) != -1) { -+ if (strncmp(line, "setup", 5)) -+ continue; -+ -+ if (line[res - 1] == '\n') -+ line[res - 1] = '\0'; -+ else if (len > res) -+ line[res] = '\0'; -+ else { -+ line = realloc(line, res + 1); -+ line[res] = '\0'; -+ } - -- free(grubDevice); -- return 0; --} -+ lastParamPtr = bounds = line + res; - --int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) { -- /* -- * This SuSE grub configuration file at this location is not your average -- * grub configuration file, but instead the grub commands used to setup -- * grub on that system. -- */ -- const char * path; -- const static char default_path[] = "/etc/grub.conf"; -+ /* Last parameter in grub may be an optional IMAGE_DEVICE */ -+ while (!isspace(*lastParamPtr)) -+ lastParamPtr--; -+ lastParamPtr++; - -- if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL) -- path = default_path; -+ secLastParamPtr = lastParamPtr - 2; -+ dbgPrintf("lastParamPtr: %s\n", lastParamPtr); - -- if (!isSuseGrubConf(path)) return 1; -+ if (lastParamPtr + 3 > bounds) { -+ dbgPrintf("lastParamPtr going over boundary"); -+ fclose(grubConf); -+ free(line); -+ return 1; -+ } -+ if (!strncmp(lastParamPtr, "(hd", 3)) -+ lastParamPtr += 3; -+ dbgPrintf("lastParamPtr: %c\n", *lastParamPtr); - -- if (lbaPtr) { -- *lbaPtr = 0; -- if (suseGrubConfGetLba(path, lbaPtr)) -- return 1; -- } -+ /* -+ * Second last parameter will decide wether last parameter is -+ * an IMAGE_DEVICE or INSTALL_DEVICE -+ */ -+ while (!isspace(*secLastParamPtr)) -+ secLastParamPtr--; -+ secLastParamPtr++; -+ -+ if (secLastParamPtr + 3 > bounds) { -+ dbgPrintf("secLastParamPtr going over boundary"); -+ fclose(grubConf); -+ free(line); -+ return 1; -+ } -+ dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr); -+ if (!strncmp(secLastParamPtr, "(hd", 3)) { -+ secLastParamPtr += 3; -+ dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr); -+ installDeviceNumber = *secLastParamPtr; -+ } else { -+ installDeviceNumber = *lastParamPtr; -+ } - -- if (bootPtr) { -- *bootPtr = NULL; -- suseGrubConfGetBoot(path, bootPtr); -- } -+ *devicePtr = malloc(6); -+ snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber); -+ dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber); -+ fclose(grubConf); -+ free(line); -+ return 0; -+ } - -- return 0; -+ free(line); -+ fclose(grubConf); -+ return 1; - } - --int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) { -- FILE * in; -- char buf[1024]; -- char * chptr; -- char * start; -- char * param; -- -- in = fopen("/etc/sysconfig/grub", "r"); -- if (!in) return 1; -+int grubGetBootFromDeviceMap(const char *device, char **bootPtr) -+{ -+ FILE *deviceMap; -+ char *line = NULL; -+ size_t res = 0, len = 0; -+ char *devicePtr; -+ char *bounds = NULL; -+ const char *path; -+ const static char default_path[] = "/boot/grub/device.map"; -+ -+ if (!device) -+ return 1; -+ if (!bootPtr) -+ return 1; - -- if (lbaPtr) *lbaPtr = 0; -- if (bootPtr) *bootPtr = NULL; -+ if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL) -+ path = default_path; - -- while (fgets(buf, sizeof(buf), in)) { -- start = buf; -- while (isspace(*start)) start++; -- if (*start == '#') continue; -+ dbgPrintf("opening grub device.map file from: %s\n", path); -+ deviceMap = fopen(path, "r"); -+ if (!deviceMap) -+ return 1; - -- chptr = strchr(start, '='); -- if (!chptr) continue; -- chptr--; -- while (*chptr && isspace(*chptr)) chptr--; -- chptr++; -- *chptr = '\0'; -+ while ((res = getline(&line, &len, deviceMap)) != -1) { -+ if (!strncmp(line, "#", 1)) -+ continue; -+ -+ if (line[res - 1] == '\n') -+ line[res - 1] = '\0'; -+ else if (len > res) -+ line[res] = '\0'; -+ else { -+ line = realloc(line, res + 1); -+ line[res] = '\0'; -+ } - -- param = chptr + 1; -- while (*param && isspace(*param)) param++; -- if (*param == '=') { -- param++; -- while (*param && isspace(*param)) param++; -- } -+ devicePtr = line; -+ bounds = line + res; - -- chptr = param; -- while (*chptr && !isspace(*chptr)) chptr++; -- *chptr = '\0'; -+ while ((isspace(*line) && ((devicePtr + 1) <= bounds))) -+ devicePtr++; -+ dbgPrintf("device: %s\n", devicePtr); - -- if (!strcmp(start, "forcelba") && !strcmp(param, "1") && lbaPtr) -- *lbaPtr = 1; -- else if (!strcmp(start, "boot") && bootPtr) -- *bootPtr = strdup(param); -- } -+ if (!strncmp(devicePtr, device, strlen(device))) { -+ devicePtr += strlen(device); -+ while (isspace(*devicePtr) -+ && ((devicePtr + 1) <= bounds)) -+ devicePtr++; - -- fclose(in); -+ *bootPtr = strdup(devicePtr); -+ break; -+ } -+ } - -- return 0; -+ free(line); -+ fclose(deviceMap); -+ return 0; - } - --void dumpSysconfigGrub(void) { -- char * boot = NULL; -- int lba; -+int suseGrubConfGetBoot(const char *path, char **bootPtr) -+{ -+ char *grubDevice; - -- if (isSuseSystem()) { -- if (parseSuseGrubConf(&lba, &boot)) { -- free(boot); -- return; -- } -- } else { -- if (parseSysconfigGrub(&lba, &boot)) { -- free(boot); -- return; -- } -- } -+ if (suseGrubConfGetInstallDevice(path, &grubDevice)) -+ dbgPrintf("error looking for grub installation device\n"); -+ else -+ dbgPrintf("grubby installation device: %s\n", grubDevice); - -- if (lba) printf("lba\n"); -- if (boot) { -- printf("boot=%s\n", boot); -- free(boot); -- } --} -+ if (grubGetBootFromDeviceMap(grubDevice, bootPtr)) -+ dbgPrintf("error looking for grub boot device\n"); -+ else -+ dbgPrintf("grubby boot device: %s\n", *bootPtr); - --int displayInfo(struct grubConfig * config, char * kernel, -- const char * prefix) { -- int i = 0; -- struct singleEntry * entry; -- struct singleLine * line; -+ free(grubDevice); -+ return 0; -+} - -- entry = findEntryByPath(config, kernel, prefix, &i); -- if (!entry) { -- fprintf(stderr, _("grubby: kernel not found\n")); -- return 1; -- } -+int parseSuseGrubConf(int *lbaPtr, char **bootPtr) -+{ -+ /* -+ * This SuSE grub configuration file at this location is not your average -+ * grub configuration file, but instead the grub commands used to setup -+ * grub on that system. -+ */ -+ const char *path; -+ const static char default_path[] = "/etc/grub.conf"; - -- /* this is a horrible hack to support /etc/sysconfig/grub; there must -- be a better way */ -- if (config->cfi == &grubConfigType) { -- dumpSysconfigGrub(); -- } else { -- line = getLineByType(LT_BOOT, config->theLines); -- if (line && line->numElements >= 1) { -- printf("boot=%s\n", line->elements[1].item); -- } -+ if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL) -+ path = default_path; - -- line = getLineByType(LT_LBA, config->theLines); -- if (line) printf("lba\n"); -- } -+ if (!isSuseGrubConf(path)) -+ return 1; - -- displayEntry(entry, prefix, i); -+ if (lbaPtr) { -+ *lbaPtr = 0; -+ if (suseGrubConfGetLba(path, lbaPtr)) -+ return 1; -+ } - -- i++; -- while ((entry = findEntryByPath(config, kernel, prefix, &i))) { -- displayEntry(entry, prefix, i); -- i++; -- } -+ if (bootPtr) { -+ *bootPtr = NULL; -+ suseGrubConfGetBoot(path, bootPtr); -+ } - -- return 0; -+ return 0; - } - --struct singleLine * addLineTmpl(struct singleEntry * entry, -- struct singleLine * tmplLine, -- struct singleLine * prevLine, -- const char * val, -- struct configFileInfo * cfi) -+int parseSysconfigGrub(int *lbaPtr, char **bootPtr) - { -- struct singleLine * newLine = lineDup(tmplLine); -- -- if (isEfi && cfi == &grub2ConfigType) { -- enum lineType_e old = newLine->type; -- newLine->type = preferredLineType(newLine->type, cfi); -- if (old != newLine->type) -- newLine->elements[0].item = getKeyByType(newLine->type, cfi); -- } -- -- if (val) { -- /* override the inherited value with our own. -- * This is a little weak because it only applies to elements[1] -- */ -- if (newLine->numElements > 1) -- removeElement(newLine, 1); -- insertElement(newLine, val, 1, cfi); -- -- /* but try to keep the rootspec from the template... sigh */ -- if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) { -- char * rootspec = getRootSpecifier(tmplLine->elements[1].item); -- if (rootspec != NULL) { -- free(newLine->elements[1].item); -- newLine->elements[1].item = -- sdupprintf("%s%s", rootspec, val); -- } -- } -- } -- -- dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ? -- newLine->elements[0].item : ""); -- -- if (!entry->lines) { -- /* first one on the list */ -- entry->lines = newLine; -- } else if (prevLine) { -- /* add after prevLine */ -- newLine->next = prevLine->next; -- prevLine->next = newLine; -- } -- -- return newLine; --} -+ FILE *in; -+ char buf[1024]; -+ char *chptr; -+ char *start; -+ char *param; -+ -+ in = fopen("/etc/sysconfig/grub", "r"); -+ if (!in) -+ return 1; - --/* val may be NULL */ --struct singleLine * addLine(struct singleEntry * entry, -- struct configFileInfo * cfi, -- enum lineType_e type, char * defaultIndent, -- const char * val) { -- struct singleLine * line, * prev; -- struct keywordTypes * kw; -- struct singleLine tmpl; -- -- /* NB: This function shouldn't allocate items on the heap, rather on the -- * stack since it calls addLineTmpl which will make copies. -- */ -- if (type == LT_TITLE && cfi->titleBracketed) { -- /* we're doing a bracketed title (zipl) */ -- tmpl.type = type; -- tmpl.numElements = 1; -- tmpl.elements = alloca(sizeof(*tmpl.elements)); -- tmpl.elements[0].item = alloca(strlen(val)+3); -- sprintf(tmpl.elements[0].item, "[%s]", val); -- tmpl.elements[0].indent = ""; -- val = NULL; -- } else if (type == LT_MENUENTRY) { -- char *lineend = "--class gnu-linux --class gnu --class os {"; -- if (!val) { -- fprintf(stderr, "Line type LT_MENUENTRY requires a value\n"); -- abort(); -- } -- kw = getKeywordByType(type, cfi); -- if (!kw) { -- fprintf(stderr, "Looking up keyword for unknown type %d\n", type); -- abort(); -- } -- tmpl.indent = ""; -- tmpl.type = type; -- tmpl.numElements = 3; -- tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements); -- tmpl.elements[0].item = kw->key; -- tmpl.elements[0].indent = alloca(2); -- sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); -- tmpl.elements[1].item = (char *)val; -- tmpl.elements[1].indent = alloca(2); -- sprintf(tmpl.elements[1].indent, "%c", kw->nextChar); -- tmpl.elements[2].item = alloca(strlen(lineend)+1); -- strcpy(tmpl.elements[2].item, lineend); -- tmpl.elements[2].indent = ""; -- } else { -- kw = getKeywordByType(type, cfi); -- if (!kw) { -- fprintf(stderr, "Looking up keyword for unknown type %d\n", type); -- abort(); -- } -- tmpl.type = type; -- tmpl.numElements = val ? 2 : 1; -- tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements); -- tmpl.elements[0].item = kw->key; -- tmpl.elements[0].indent = alloca(2); -- sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); -- if (val) { -- tmpl.elements[1].item = (char *)val; -- tmpl.elements[1].indent = ""; -- } -- } -- -- /* The last non-empty line gives us the indention to us and the line -- to insert after. Note that comments are considered empty lines, which -- may not be ideal? If there are no lines or we are looking at the -- first line, we use defaultIndent (the first line is normally indented -- differently from the rest) */ -- for (line = entry->lines, prev = NULL; line; line = line->next) { -- if (line->numElements) prev = line; -- /* fall back on the last line if prev isn't otherwise set */ -- if (!line->next && !prev) prev = line; -- } -- -- struct singleLine *menuEntry; -- menuEntry = getLineByType(LT_MENUENTRY, entry->lines); -- if (tmpl.type == LT_ENTRY_END) { -- if (menuEntry) -- tmpl.indent = menuEntry->indent; -- else -- tmpl.indent = defaultIndent ?: ""; -- } else if (tmpl.type != LT_MENUENTRY) { -- if (menuEntry) -- tmpl.indent = "\t"; -- else if (prev == entry->lines) -- tmpl.indent = defaultIndent ?: ""; -- else -- tmpl.indent = prev->indent; -- } -+ if (lbaPtr) -+ *lbaPtr = 0; -+ if (bootPtr) -+ *bootPtr = NULL; -+ -+ while (fgets(buf, sizeof(buf), in)) { -+ start = buf; -+ while (isspace(*start)) -+ start++; -+ if (*start == '#') -+ continue; -+ -+ chptr = strchr(start, '='); -+ if (!chptr) -+ continue; -+ chptr--; -+ while (*chptr && isspace(*chptr)) -+ chptr--; -+ chptr++; -+ *chptr = '\0'; -+ -+ param = chptr + 1; -+ while (*param && isspace(*param)) -+ param++; -+ if (*param == '=') { -+ param++; -+ while (*param && isspace(*param)) -+ param++; -+ } - -- return addLineTmpl(entry, &tmpl, prev, val, cfi); --} -+ chptr = param; -+ while (*chptr && !isspace(*chptr)) -+ chptr++; -+ *chptr = '\0'; -+ -+ if (!strcmp(start, "forcelba") && !strcmp(param, "1") && lbaPtr) -+ *lbaPtr = 1; -+ else if (!strcmp(start, "boot") && bootPtr) -+ *bootPtr = strdup(param); -+ } - --void removeLine(struct singleEntry * entry, struct singleLine * line) { -- struct singleLine * prev; -- int i; -- -- for (i = 0; i < line->numElements; i++) { -- free(line->elements[i].item); -- free(line->elements[i].indent); -- } -- free(line->elements); -- free(line->indent); -- -- if (line == entry->lines) { -- entry->lines = line->next; -- } else { -- prev = entry->lines; -- while (prev->next != line) prev = prev->next; -- prev->next = line->next; -- } -- -- free(line); -+ fclose(in); -+ -+ return 0; - } - --static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi) -+void dumpSysconfigGrub(void) - { -- struct singleLine newLine = { -- .indent = tmplLine->indent, -- .type = tmplLine->type, -- .next = tmplLine->next, -- }; -- int firstQuotedItem = -1; -- int quoteLen = 0; -- int j; -- int element = 0; -- char *c; -- -- c = malloc(strlen(tmplLine->elements[0].item) + 1); -- strcpy(c, tmplLine->elements[0].item); -- insertElement(&newLine, c, element++, cfi); -- free(c); -- c = NULL; -- -- for (j = 1; j < tmplLine->numElements; j++) { -- if (firstQuotedItem == -1) { -- quoteLen += strlen(tmplLine->elements[j].item); -- -- if (isquote(tmplLine->elements[j].item[0])) { -- firstQuotedItem = j; -- quoteLen += strlen(tmplLine->elements[j].indent); -- } else { -- c = malloc(quoteLen + 1); -- strcpy(c, tmplLine->elements[j].item); -- insertElement(&newLine, c, element++, cfi); -- free(c); -- quoteLen = 0; -- } -+ char *boot = NULL; -+ int lba; -+ -+ if (isSuseSystem()) { -+ if (parseSuseGrubConf(&lba, &boot)) { -+ free(boot); -+ return; -+ } - } else { -- int itemlen = strlen(tmplLine->elements[j].item); -- quoteLen += itemlen; -- quoteLen += strlen(tmplLine->elements[j].indent); -- -- if (isquote(tmplLine->elements[j].item[itemlen - 1])) { -- c = malloc(quoteLen + 1); -- c[0] = '\0'; -- for (int i = firstQuotedItem; i < j+1; i++) { -- strcat(c, tmplLine->elements[i].item); -- strcat(c, tmplLine->elements[i].indent); -+ if (parseSysconfigGrub(&lba, &boot)) { -+ free(boot); -+ return; - } -- insertElement(&newLine, c, element++, cfi); -- free(c); -- -- firstQuotedItem = -1; -- quoteLen = 0; -- } -- } -- } -- while (tmplLine->numElements) -- removeElement(tmplLine, 0); -- if (tmplLine->elements) -- free(tmplLine->elements); -- -- tmplLine->numElements = newLine.numElements; -- tmplLine->elements = newLine.elements; --} -+ } - --static void insertElement(struct singleLine * line, -- const char * item, int insertHere, -- struct configFileInfo * cfi) --{ -- struct keywordTypes * kw; -- char indent[2] = ""; -- -- /* sanity check */ -- if (insertHere > line->numElements) { -- dbgPrintf("insertElement() adjusting insertHere from %d to %d\n", -- insertHere, line->numElements); -- insertHere = line->numElements; -- } -- -- line->elements = realloc(line->elements, (line->numElements + 1) * -- sizeof(*line->elements)); -- memmove(&line->elements[insertHere+1], -- &line->elements[insertHere], -- (line->numElements - insertHere) * -- sizeof(*line->elements)); -- line->elements[insertHere].item = strdup(item); -- -- kw = getKeywordByType(line->type, cfi); -- -- if (line->numElements == 0) { -- indent[0] = '\0'; -- } else if (insertHere == 0) { -- indent[0] = kw->nextChar; -- } else if (kw->separatorChar != '\0') { -- indent[0] = kw->separatorChar; -- } else { -- indent[0] = ' '; -- } -- -- if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') { -- /* move the end-of-line forward */ -- line->elements[insertHere].indent = -- line->elements[insertHere-1].indent; -- line->elements[insertHere-1].indent = strdup(indent); -- } else { -- line->elements[insertHere].indent = strdup(indent); -- } -- -- line->numElements++; -- -- dbgPrintf("insertElement(%s, '%s%s', %d)\n", -- line->elements[0].item, -- line->elements[insertHere].item, -- line->elements[insertHere].indent, -- insertHere); -+ if (lba) -+ printf("lba\n"); -+ if (boot) { -+ printf("boot=%s\n", boot); -+ free(boot); -+ } - } - --static void removeElement(struct singleLine * line, int removeHere) { -- int i; -+int displayInfo(struct grubConfig *config, char *kernel, const char *prefix) -+{ -+ int i = 0; -+ struct singleEntry *entry; -+ struct singleLine *line; - -- /* sanity check */ -- if (removeHere >= line->numElements) return; -+ entry = findEntryByPath(config, kernel, prefix, &i); -+ if (!entry) { -+ fprintf(stderr, _("grubby: kernel not found\n")); -+ return 1; -+ } - -- dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item, -- removeHere, line->elements[removeHere].item); -+ /* this is a horrible hack to support /etc/sysconfig/grub; there must -+ be a better way */ -+ if (config->cfi == &grubConfigType) { -+ dumpSysconfigGrub(); -+ } else { -+ line = getLineByType(LT_BOOT, config->theLines); -+ if (line && line->numElements >= 1) { -+ printf("boot=%s\n", line->elements[1].item); -+ } - -- free(line->elements[removeHere].item); -+ line = getLineByType(LT_LBA, config->theLines); -+ if (line) -+ printf("lba\n"); -+ } - -- if (removeHere > 1) { -- /* previous argument gets this argument's post-indentation */ -- free(line->elements[removeHere-1].indent); -- line->elements[removeHere-1].indent = -- line->elements[removeHere].indent; -- } else { -- free(line->elements[removeHere].indent); -- } -+ displayEntry(entry, prefix, i); - -- /* now collapse the array, but don't bother to realloc smaller */ -- for (i = removeHere; i < line->numElements - 1; i++) -- line->elements[i] = line->elements[i + 1]; -+ i++; -+ while ((entry = findEntryByPath(config, kernel, prefix, &i))) { -+ displayEntry(entry, prefix, i); -+ i++; -+ } - -- line->numElements--; -+ return 0; - } - --int argMatch(const char * one, const char * two) { -- char * first, * second; -- char * chptr; -+struct singleLine *addLineTmpl(struct singleEntry *entry, -+ struct singleLine *tmplLine, -+ struct singleLine *prevLine, -+ const char *val, struct configFileInfo *cfi) -+{ -+ struct singleLine *newLine = lineDup(tmplLine); -+ -+ if (isEfi && cfi == &grub2ConfigType) { -+ enum lineType_e old = newLine->type; -+ newLine->type = preferredLineType(newLine->type, cfi); -+ if (old != newLine->type) -+ newLine->elements[0].item = -+ getKeyByType(newLine->type, cfi); -+ } - -- first = strcpy(alloca(strlen(one) + 1), one); -- second = strcpy(alloca(strlen(two) + 1), two); -+ if (val) { -+ /* override the inherited value with our own. -+ * This is a little weak because it only applies to elements[1] -+ */ -+ if (newLine->numElements > 1) -+ removeElement(newLine, 1); -+ insertElement(newLine, val, 1, cfi); -+ -+ /* but try to keep the rootspec from the template... sigh */ -+ if (tmplLine-> -+ type & (LT_HYPER | LT_KERNEL | LT_MBMODULE | LT_INITRD | -+ LT_KERNEL_EFI | LT_INITRD_EFI | LT_KERNEL_16 | -+ LT_INITRD_16)) { -+ char *rootspec = -+ getRootSpecifier(tmplLine->elements[1].item); -+ if (rootspec != NULL) { -+ free(newLine->elements[1].item); -+ newLine->elements[1].item = -+ sdupprintf("%s%s", rootspec, val); -+ } -+ } -+ } - -- chptr = strchr(first, '='); -- if (chptr) *chptr = '\0'; -+ dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ? -+ newLine->elements[0].item : ""); - -- chptr = strchr(second, '='); -- if (chptr) *chptr = '\0'; -+ if (!entry->lines) { -+ /* first one on the list */ -+ entry->lines = newLine; -+ } else if (prevLine) { -+ /* add after prevLine */ -+ newLine->next = prevLine->next; -+ prevLine->next = newLine; -+ } - -- return strcmp(first, second); -+ return newLine; - } - --int updateActualImage(struct grubConfig * cfg, const char * image, -- const char * prefix, const char * addArgs, -- const char * removeArgs, int multibootArgs) { -- struct singleEntry * entry; -- struct singleLine * line, * rootLine; -- int index = 0; -- int i, k; -- const char ** newArgs, ** oldArgs; -- const char ** arg; -- int useKernelArgs, useRoot; -- int firstElement; -- int *usedElements; -- int doreplace; -- -- if (!image) return 0; -- -- if (!addArgs) { -- newArgs = malloc(sizeof(*newArgs)); -- *newArgs = NULL; -- } else { -- if (poptParseArgvString(addArgs, NULL, &newArgs)) { -- fprintf(stderr, -- _("grubby: error separating arguments '%s'\n"), addArgs); -- return 1; -- } -- } -- -- if (!removeArgs) { -- oldArgs = malloc(sizeof(*oldArgs)); -- *oldArgs = NULL; -- } else { -- if (poptParseArgvString(removeArgs, NULL, &oldArgs)) { -- fprintf(stderr, -- _("grubby: error separating arguments '%s'\n"), removeArgs); -- free(newArgs); -- return 1; -- } -- } -- -- -- useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi) -- && (!multibootArgs || cfg->cfi->mbConcatArgs)); -- -- useRoot = (getKeywordByType(LT_ROOT, cfg->cfi) -- && !multibootArgs); -- -- for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { -- -- if (multibootArgs && !entry->multiboot) -- continue; -- -- /* Determine where to put the args. If this config supports -- * LT_KERNELARGS, use that. Otherwise use -- * LT_HYPER/LT_KERNEL/LT_MBMODULE lines. -- */ -- if (useKernelArgs) { -- line = getLineByType(LT_KERNELARGS, entry->lines); -- if (!line) { -- /* no LT_KERNELARGS, need to add it */ -- line = addLine(entry, cfg->cfi, LT_KERNELARGS, -- cfg->secondaryIndent, NULL); -- } -- firstElement = 1; -- -- } else if (multibootArgs) { -- line = getLineByType(LT_HYPER, entry->lines); -- if (!line) { -- /* a multiboot entry without LT_HYPER? */ -- continue; -- } -- firstElement = 2; -- -- } else { -- line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); -- if (!line) { -- /* no LT_KERNEL or LT_MBMODULE in this entry? */ -- continue; -- } -- firstElement = 2; -- } -+/* val may be NULL */ -+struct singleLine *addLine(struct singleEntry *entry, -+ struct configFileInfo *cfi, -+ enum lineType_e type, char *defaultIndent, -+ const char *val) -+{ -+ struct singleLine *line, *prev; -+ struct keywordTypes *kw; -+ struct singleLine tmpl; - -- /* handle the elilo case which does: -- * append="hypervisor args -- kernel args" -+ /* NB: This function shouldn't allocate items on the heap, rather on the -+ * stack since it calls addLineTmpl which will make copies. - */ -- if (entry->multiboot && cfg->cfi->mbConcatArgs) { -- /* this is a multiboot entry, make sure there's -- * -- on the args line -- */ -- for (i = firstElement; i < line->numElements; i++) { -- if (!strcmp(line->elements[i].item, "--")) -- break; -- } -- if (i == line->numElements) { -- /* assume all existing args are kernel args, -- * prepend -- to make it official -- */ -- insertElement(line, "--", firstElement, cfg->cfi); -- i = firstElement; -- } -- if (!multibootArgs) { -- /* kernel args start after the -- */ -- firstElement = i + 1; -- } -- } else if (cfg->cfi->mbConcatArgs) { -- /* this is a non-multiboot entry, remove hyper args */ -- for (i = firstElement; i < line->numElements; i++) { -- if (!strcmp(line->elements[i].item, "--")) -- break; -- } -- if (i < line->numElements) { -- /* remove args up to -- */ -- while (strcmp(line->elements[firstElement].item, "--")) -- removeElement(line, firstElement); -- /* remove -- */ -- removeElement(line, firstElement); -- } -- } -- -- usedElements = calloc(line->numElements, sizeof(*usedElements)); -- -- for (k = 0, arg = newArgs; *arg; arg++, k++) { -- -- doreplace = 1; -- for (i = firstElement; i < line->numElements; i++) { -- if (multibootArgs && cfg->cfi->mbConcatArgs && -- !strcmp(line->elements[i].item, "--")) -- { -- /* reached the end of hyper args, insert here */ -- doreplace = 0; -- break; -+ if (type == LT_TITLE && cfi->titleBracketed) { -+ /* we're doing a bracketed title (zipl) */ -+ tmpl.type = type; -+ tmpl.numElements = 1; -+ tmpl.elements = alloca(sizeof(*tmpl.elements)); -+ tmpl.elements[0].item = alloca(strlen(val) + 3); -+ sprintf(tmpl.elements[0].item, "[%s]", val); -+ tmpl.elements[0].indent = ""; -+ val = NULL; -+ } else if (type == LT_MENUENTRY) { -+ char *lineend = "--class gnu-linux --class gnu --class os {"; -+ if (!val) { -+ fprintf(stderr, -+ "Line type LT_MENUENTRY requires a value\n"); -+ abort(); - } -- if (usedElements[i]) -- continue; -- if (!argMatch(line->elements[i].item, *arg)) { -- usedElements[i]=1; -- break; -- } -- } -- -- if (i < line->numElements && doreplace) { -- /* direct replacement */ -- free(line->elements[i].item); -- line->elements[i].item = strdup(*arg); -- -- } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) { -- /* root= replacement */ -- rootLine = getLineByType(LT_ROOT, entry->lines); -- if (rootLine) { -- free(rootLine->elements[1].item); -- rootLine->elements[1].item = strdup(*arg + 5); -- } else { -- rootLine = addLine(entry, cfg->cfi, LT_ROOT, -- cfg->secondaryIndent, *arg + 5); -+ kw = getKeywordByType(type, cfi); -+ if (!kw) { -+ fprintf(stderr, -+ "Looking up keyword for unknown type %d\n", -+ type); -+ abort(); - } -- } -- -- else { -- /* insert/append */ -- insertElement(line, *arg, i, cfg->cfi); -- usedElements = realloc(usedElements, line->numElements * -- sizeof(*usedElements)); -- memmove(&usedElements[i + 1], &usedElements[i], -- line->numElements - i - 1); -- usedElements[i] = 1; -- -- /* if we updated a root= here even though there is a -- LT_ROOT available we need to remove the LT_ROOT entry -- (this will happen if we switch from a device to a label) */ -- if (useRoot && !strncmp(*arg, "root=", 5)) { -- rootLine = getLineByType(LT_ROOT, entry->lines); -- if (rootLine) -- removeLine(entry, rootLine); -+ tmpl.indent = ""; -+ tmpl.type = type; -+ tmpl.numElements = 3; -+ tmpl.elements = -+ alloca(sizeof(*tmpl.elements) * tmpl.numElements); -+ tmpl.elements[0].item = kw->key; -+ tmpl.elements[0].indent = alloca(2); -+ sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); -+ tmpl.elements[1].item = (char *)val; -+ tmpl.elements[1].indent = alloca(2); -+ sprintf(tmpl.elements[1].indent, "%c", kw->nextChar); -+ tmpl.elements[2].item = alloca(strlen(lineend) + 1); -+ strcpy(tmpl.elements[2].item, lineend); -+ tmpl.elements[2].indent = ""; -+ } else { -+ kw = getKeywordByType(type, cfi); -+ if (!kw) { -+ fprintf(stderr, -+ "Looking up keyword for unknown type %d\n", -+ type); -+ abort(); - } -- } -- } -- -- free(usedElements); -- -- for (arg = oldArgs; *arg; arg++) { -- for (i = firstElement; i < line->numElements; i++) { -- if (multibootArgs && cfg->cfi->mbConcatArgs && -- !strcmp(line->elements[i].item, "--")) -- /* reached the end of hyper args, stop here */ -- break; -- if (!argMatch(line->elements[i].item, *arg)) { -- removeElement(line, i); -- break; -+ tmpl.type = type; -+ tmpl.numElements = val ? 2 : 1; -+ tmpl.elements = -+ alloca(sizeof(*tmpl.elements) * tmpl.numElements); -+ tmpl.elements[0].item = kw->key; -+ tmpl.elements[0].indent = alloca(2); -+ sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); -+ if (val) { -+ tmpl.elements[1].item = (char *)val; -+ tmpl.elements[1].indent = ""; - } -- } -- /* handle removing LT_ROOT line too */ -- if (useRoot && !strncmp(*arg, "root=", 5)) { -- rootLine = getLineByType(LT_ROOT, entry->lines); -- if (rootLine) -- removeLine(entry, rootLine); -- } - } - -- if (line->numElements == 1) { -- /* don't need the line at all (note it has to be a -- LT_KERNELARGS for this to happen */ -- removeLine(entry, line); -+ /* The last non-empty line gives us the indention to us and the line -+ to insert after. Note that comments are considered empty lines, which -+ may not be ideal? If there are no lines or we are looking at the -+ first line, we use defaultIndent (the first line is normally indented -+ differently from the rest) */ -+ for (line = entry->lines, prev = NULL; line; line = line->next) { -+ if (line->numElements) -+ prev = line; -+ /* fall back on the last line if prev isn't otherwise set */ -+ if (!line->next && !prev) -+ prev = line; - } -- } - -- free(newArgs); -- free(oldArgs); -+ struct singleLine *menuEntry; -+ menuEntry = getLineByType(LT_MENUENTRY, entry->lines); -+ if (tmpl.type == LT_ENTRY_END) { -+ if (menuEntry) -+ tmpl.indent = menuEntry->indent; -+ else -+ tmpl.indent = defaultIndent ? : ""; -+ } else if (tmpl.type != LT_MENUENTRY) { -+ if (menuEntry) -+ tmpl.indent = "\t"; -+ else if (prev == entry->lines) -+ tmpl.indent = defaultIndent ? : ""; -+ else -+ tmpl.indent = prev->indent; -+ } - -- return 0; -+ return addLineTmpl(entry, &tmpl, prev, val, cfi); - } - --int updateImage(struct grubConfig * cfg, const char * image, -- const char * prefix, const char * addArgs, -- const char * removeArgs, -- const char * addMBArgs, const char * removeMBArgs) { -- int rc = 0; -+void removeLine(struct singleEntry *entry, struct singleLine *line) -+{ -+ struct singleLine *prev; -+ int i; - -- if (!image) return rc; -+ for (i = 0; i < line->numElements; i++) { -+ free(line->elements[i].item); -+ free(line->elements[i].indent); -+ } -+ free(line->elements); -+ free(line->indent); - -- /* update the main args first... */ -- if (addArgs || removeArgs) -- rc = updateActualImage(cfg, image, prefix, addArgs, removeArgs, 0); -- if (rc) return rc; -+ if (line == entry->lines) { -+ entry->lines = line->next; -+ } else { -+ prev = entry->lines; -+ while (prev->next != line) -+ prev = prev->next; -+ prev->next = line->next; -+ } - -- /* and now any multiboot args */ -- if (addMBArgs || removeMBArgs) -- rc = updateActualImage(cfg, image, prefix, addMBArgs, removeMBArgs, 1); -- return rc; -+ free(line); - } - --int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel, -- const char * image, const char * prefix, const char * initrd, -- const char * title) { -- struct singleEntry * entry; -- struct singleLine * line, * kernelLine, *endLine = NULL; -- int index = 0; -- -- if (!image) return 0; -- -- for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) { -- kernelLine = getLineByType(LT_MBMODULE, entry->lines); -- if (!kernelLine) continue; -- -- /* if title is supplied, the entry's title must match it. */ -- if (title) { -- char *linetitle; -- -- line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines); -- if (!line) -- continue; -- -- linetitle = extractTitle(cfg, line); -- if (!linetitle) -- continue; -- if (strcmp(title, linetitle)) { -- free(linetitle); -- continue; -- } -- free(linetitle); -- } -- -- if (prefix) { -- int prefixLen = strlen(prefix); -- if (!strncmp(initrd, prefix, prefixLen)) -- initrd += prefixLen; -- } -- endLine = getLineByType(LT_ENTRY_END, entry->lines); -- if (endLine) -- removeLine(entry, endLine); -- line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi), -- kernelLine->indent, initrd); -- if (!line) -- return 1; -- if (endLine) { -- line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); -- if (!line) -- return 1; -- } -+static void requote(struct singleLine *tmplLine, struct configFileInfo *cfi) -+{ -+ struct singleLine newLine = { -+ .indent = tmplLine->indent, -+ .type = tmplLine->type, -+ .next = tmplLine->next, -+ }; -+ int firstQuotedItem = -1; -+ int quoteLen = 0; -+ int j; -+ int element = 0; -+ char *c; -+ -+ c = malloc(strlen(tmplLine->elements[0].item) + 1); -+ strcpy(c, tmplLine->elements[0].item); -+ insertElement(&newLine, c, element++, cfi); -+ free(c); -+ c = NULL; -+ -+ for (j = 1; j < tmplLine->numElements; j++) { -+ if (firstQuotedItem == -1) { -+ quoteLen += strlen(tmplLine->elements[j].item); -+ -+ if (isquote(tmplLine->elements[j].item[0])) { -+ firstQuotedItem = j; -+ quoteLen += -+ strlen(tmplLine->elements[j].indent); -+ } else { -+ c = malloc(quoteLen + 1); -+ strcpy(c, tmplLine->elements[j].item); -+ insertElement(&newLine, c, element++, cfi); -+ free(c); -+ quoteLen = 0; -+ } -+ } else { -+ int itemlen = strlen(tmplLine->elements[j].item); -+ quoteLen += itemlen; -+ quoteLen += strlen(tmplLine->elements[j].indent); -+ -+ if (isquote(tmplLine->elements[j].item[itemlen - 1])) { -+ c = malloc(quoteLen + 1); -+ c[0] = '\0'; -+ for (int i = firstQuotedItem; i < j + 1; i++) { -+ strcat(c, tmplLine->elements[i].item); -+ strcat(c, tmplLine->elements[i].indent); -+ } -+ insertElement(&newLine, c, element++, cfi); -+ free(c); - -- break; -- } -+ firstQuotedItem = -1; -+ quoteLen = 0; -+ } -+ } -+ } -+ while (tmplLine->numElements) -+ removeElement(tmplLine, 0); -+ if (tmplLine->elements) -+ free(tmplLine->elements); - -- return 0; -+ tmplLine->numElements = newLine.numElements; -+ tmplLine->elements = newLine.elements; - } - --int updateInitrd(struct grubConfig * cfg, const char * image, -- const char * prefix, const char * initrd, const char * title) { -- struct singleEntry * entry; -- struct singleLine * line, * kernelLine, *endLine = NULL; -- int index = 0; -- -- if (!image) return 0; -- -- for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { -- kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); -- if (!kernelLine) continue; -- -- /* if title is supplied, the entry's title must match it. */ -- if (title) { -- char *linetitle; -- -- line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines); -- if (!line) -- continue; -- -- linetitle = extractTitle(cfg, line); -- if (!linetitle) -- continue; -- if (strcmp(title, linetitle)) { -- free(linetitle); -- continue; -- } -- free(linetitle); -- } -- -- line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines); -- if (line) -- removeLine(entry, line); -- if (prefix) { -- int prefixLen = strlen(prefix); -- if (!strncmp(initrd, prefix, prefixLen)) -- initrd += prefixLen; -- } -- endLine = getLineByType(LT_ENTRY_END, entry->lines); -- if (endLine) -- removeLine(entry, endLine); -- enum lineType_e lt; -- switch(kernelLine->type) { -- case LT_KERNEL: -- lt = LT_INITRD; -- break; -- case LT_KERNEL_EFI: -- lt = LT_INITRD_EFI; -- break; -- case LT_KERNEL_16: -- lt = LT_INITRD_16; -- break; -- default: -- lt = preferredLineType(LT_INITRD, cfg->cfi); -+static void insertElement(struct singleLine *line, -+ const char *item, int insertHere, -+ struct configFileInfo *cfi) -+{ -+ struct keywordTypes *kw; -+ char indent[2] = ""; -+ -+ /* sanity check */ -+ if (insertHere > line->numElements) { -+ dbgPrintf -+ ("insertElement() adjusting insertHere from %d to %d\n", -+ insertHere, line->numElements); -+ insertHere = line->numElements; - } -- line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd); -- if (!line) -- return 1; -- if (endLine) { -- line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); -- if (!line) -- return 1; -+ -+ line->elements = realloc(line->elements, (line->numElements + 1) * -+ sizeof(*line->elements)); -+ memmove(&line->elements[insertHere + 1], -+ &line->elements[insertHere], -+ (line->numElements - insertHere) * sizeof(*line->elements)); -+ line->elements[insertHere].item = strdup(item); -+ -+ kw = getKeywordByType(line->type, cfi); -+ -+ if (line->numElements == 0) { -+ indent[0] = '\0'; -+ } else if (insertHere == 0) { -+ indent[0] = kw->nextChar; -+ } else if (kw->separatorChar != '\0') { -+ indent[0] = kw->separatorChar; -+ } else { -+ indent[0] = ' '; -+ } -+ -+ if (insertHere > 0 && line->elements[insertHere - 1].indent[0] == '\0') { -+ /* move the end-of-line forward */ -+ line->elements[insertHere].indent = -+ line->elements[insertHere - 1].indent; -+ line->elements[insertHere - 1].indent = strdup(indent); -+ } else { -+ line->elements[insertHere].indent = strdup(indent); - } - -- break; -- } -+ line->numElements++; - -- return 0; -+ dbgPrintf("insertElement(%s, '%s%s', %d)\n", -+ line->elements[0].item, -+ line->elements[insertHere].item, -+ line->elements[insertHere].indent, insertHere); - } - --int checkDeviceBootloader(const char * device, const unsigned char * boot) { -- int fd; -- unsigned char bootSect[512]; -- int offset; -+static void removeElement(struct singleLine *line, int removeHere) -+{ -+ int i; - -- fd = open(device, O_RDONLY); -- if (fd < 0) { -- fprintf(stderr, _("grubby: unable to open %s: %s\n"), -- device, strerror(errno)); -- return 1; -- } -+ /* sanity check */ -+ if (removeHere >= line->numElements) -+ return; - -- if (read(fd, bootSect, 512) != 512) { -- fprintf(stderr, _("grubby: unable to read %s: %s\n"), -- device, strerror(errno)); -- return 1; -- } -- close(fd); -+ dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item, -+ removeHere, line->elements[removeHere].item); - -- /* first three bytes should match, a jmp short should be in there */ -- if (memcmp(boot, bootSect, 3)) -- return 0; -+ free(line->elements[removeHere].item); - -- if (boot[1] == JMP_SHORT_OPCODE) { -- offset = boot[2] + 2; -- } else if (boot[1] == 0xe8 || boot[1] == 0xe9) { -- offset = (boot[3] << 8) + boot[2] + 2; -- } else if (boot[0] == JMP_SHORT_OPCODE) { -- offset = boot[1] + 2; -- /* -- * it looks like grub, when copying stage1 into the mbr, patches stage1 -- * right after the JMP location, replacing other instructions such as -- * JMPs for NOOPs. So, relax the check a little bit by skipping those -- * different bytes. -- */ -- if ((bootSect[offset + 1] == NOOP_OPCODE) -- && (bootSect[offset + 2] == NOOP_OPCODE)) { -- offset = offset + 3; -- } -- } else if (boot[0] == 0xe8 || boot[0] == 0xe9) { -- offset = (boot[2] << 8) + boot[1] + 2; -- } else { -- return 0; -- } -+ if (removeHere > 1) { -+ /* previous argument gets this argument's post-indentation */ -+ free(line->elements[removeHere - 1].indent); -+ line->elements[removeHere - 1].indent = -+ line->elements[removeHere].indent; -+ } else { -+ free(line->elements[removeHere].indent); -+ } - -- if (memcmp(boot + offset, bootSect + offset, CODE_SEG_SIZE)) -- return 0; -+ /* now collapse the array, but don't bother to realloc smaller */ -+ for (i = removeHere; i < line->numElements - 1; i++) -+ line->elements[i] = line->elements[i + 1]; - -- return 2; -+ line->numElements--; - } - --int checkLiloOnRaid(char * mdDev, const unsigned char * boot) { -- int fd; -- char buf[65536]; -- char * end; -- char * chptr; -- char * chptr2; -- int rc; -- -- /* it's on raid; we need to parse /proc/mdstat and check all of the -- *raw* devices listed in there */ -+int argMatch(const char *one, const char *two) -+{ -+ char *first, *second; -+ char *chptr; - -- if (!strncmp(mdDev, "/dev/", 5)) -- mdDev += 5; -+ first = strcpy(alloca(strlen(one) + 1), one); -+ second = strcpy(alloca(strlen(two) + 1), two); - -- if ((fd = open("/proc/mdstat", O_RDONLY)) < 0) { -- fprintf(stderr, _("grubby: failed to open /proc/mdstat: %s\n"), -- strerror(errno)); -- return 2; -- } -+ chptr = strchr(first, '='); -+ if (chptr) -+ *chptr = '\0'; - -- rc = read(fd, buf, sizeof(buf) - 1); -- if (rc < 0 || rc == (sizeof(buf) - 1)) { -- fprintf(stderr, _("grubby: failed to read /proc/mdstat: %s\n"), -- strerror(errno)); -- close(fd); -- return 2; -- } -- close(fd); -- buf[rc] = '\0'; -- -- chptr = buf; -- while (*chptr) { -- end = strchr(chptr, '\n'); -- if (!end) break; -- *end = '\0'; -+ chptr = strchr(second, '='); -+ if (chptr) -+ *chptr = '\0'; - -- if (!strncmp(chptr, mdDev, strlen(mdDev)) && -- chptr[strlen(mdDev)] == ' ') { -- -- /* found the device */ -- while (*chptr && *chptr != ':') chptr++; -- chptr++; -- while (*chptr && isspace(*chptr)) chptr++; -- -- /* skip the "active" bit */ -- while (*chptr && !isspace(*chptr)) chptr++; -- while (*chptr && isspace(*chptr)) chptr++; -- -- /* skip the raid level */ -- while (*chptr && !isspace(*chptr)) chptr++; -- while (*chptr && isspace(*chptr)) chptr++; -- -- /* everything else is partition stuff */ -- while (*chptr) { -- chptr2 = chptr; -- while (*chptr2 && *chptr2 != '[') chptr2++; -- if (!*chptr2) break; -- -- /* yank off the numbers at the end */ -- chptr2--; -- while (isdigit(*chptr2) && chptr2 > chptr) chptr2--; -- chptr2++; -- *chptr2 = '\0'; -- -- /* Better, now we need the /dev/ back. We're done with -- * everything before this point, so we can just put -- * the /dev/ part there. There will always be room. */ -- memcpy(chptr - 5, "/dev/", 5); -- rc = checkDeviceBootloader(chptr - 5, boot); -- if (rc != 2) { -- return rc; -- } -+ return strcmp(first, second); -+} - -- chptr = chptr2 + 1; -- /* skip the [11] bit */ -- while (*chptr && !isspace(*chptr)) chptr++; -- /* and move to the next one */ -- while (*chptr && isspace(*chptr)) chptr++; -- } -+int updateActualImage(struct grubConfig *cfg, const char *image, -+ const char *prefix, const char *addArgs, -+ const char *removeArgs, int multibootArgs) -+{ -+ struct singleEntry *entry; -+ struct singleLine *line, *rootLine; -+ int index = 0; -+ int i, k; -+ const char **newArgs, **oldArgs; -+ const char **arg; -+ int useKernelArgs, useRoot; -+ int firstElement; -+ int *usedElements; -+ int doreplace; -+ -+ if (!image) -+ return 0; - -- /* we're good to go */ -- return 2; -+ if (!addArgs) { -+ newArgs = malloc(sizeof(*newArgs)); -+ *newArgs = NULL; -+ } else { -+ if (poptParseArgvString(addArgs, NULL, &newArgs)) { -+ fprintf(stderr, -+ _("grubby: error separating arguments '%s'\n"), -+ addArgs); -+ return 1; -+ } - } - -- chptr = end + 1; -- } -+ if (!removeArgs) { -+ oldArgs = malloc(sizeof(*oldArgs)); -+ *oldArgs = NULL; -+ } else { -+ if (poptParseArgvString(removeArgs, NULL, &oldArgs)) { -+ fprintf(stderr, -+ _("grubby: error separating arguments '%s'\n"), -+ removeArgs); -+ free(newArgs); -+ return 1; -+ } -+ } - -- fprintf(stderr, -- _("grubby: raid device /dev/%s not found in /proc/mdstat\n"), -- mdDev); -- return 0; --} -+ useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi) -+ && (!multibootArgs || cfg->cfi->mbConcatArgs)); - --int checkForLilo(struct grubConfig * config) { -- int fd; -- unsigned char boot[512]; -- struct singleLine * line; -+ useRoot = (getKeywordByType(LT_ROOT, cfg->cfi) -+ && !multibootArgs); - -- for (line = config->theLines; line; line = line->next) -- if (line->type == LT_BOOT) break; -+ for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { - -- if (!line) { -- fprintf(stderr, -- _("grubby: no boot line found in lilo configuration\n")); -- return 1; -- } -+ if (multibootArgs && !entry->multiboot) -+ continue; - -- if (line->numElements != 2) return 1; -+ /* Determine where to put the args. If this config supports -+ * LT_KERNELARGS, use that. Otherwise use -+ * LT_HYPER/LT_KERNEL/LT_MBMODULE lines. -+ */ -+ if (useKernelArgs) { -+ line = getLineByType(LT_KERNELARGS, entry->lines); -+ if (!line) { -+ /* no LT_KERNELARGS, need to add it */ -+ line = addLine(entry, cfg->cfi, LT_KERNELARGS, -+ cfg->secondaryIndent, NULL); -+ } -+ firstElement = 1; - -- fd = open("/boot/boot.b", O_RDONLY); -- if (fd < 0) { -- fprintf(stderr, _("grubby: unable to open %s: %s\n"), -- "/boot/boot.b", strerror(errno)); -- return 1; -- } -+ } else if (multibootArgs) { -+ line = getLineByType(LT_HYPER, entry->lines); -+ if (!line) { -+ /* a multiboot entry without LT_HYPER? */ -+ continue; -+ } -+ firstElement = 2; - -- if (read(fd, boot, 512) != 512) { -- fprintf(stderr, _("grubby: unable to read %s: %s\n"), -- "/boot/boot.b", strerror(errno)); -- return 1; -- } -- close(fd); -+ } else { -+ line = -+ getLineByType(LT_KERNEL | LT_MBMODULE | -+ LT_KERNEL_EFI | LT_KERNEL_16, -+ entry->lines); -+ if (!line) { -+ /* no LT_KERNEL or LT_MBMODULE in this entry? */ -+ continue; -+ } -+ firstElement = 2; -+ } - -- if (!strncmp("/dev/md", line->elements[1].item, 7)) -- return checkLiloOnRaid(line->elements[1].item, boot); -+ /* handle the elilo case which does: -+ * append="hypervisor args -- kernel args" -+ */ -+ if (entry->multiboot && cfg->cfi->mbConcatArgs) { -+ /* this is a multiboot entry, make sure there's -+ * -- on the args line -+ */ -+ for (i = firstElement; i < line->numElements; i++) { -+ if (!strcmp(line->elements[i].item, "--")) -+ break; -+ } -+ if (i == line->numElements) { -+ /* assume all existing args are kernel args, -+ * prepend -- to make it official -+ */ -+ insertElement(line, "--", firstElement, -+ cfg->cfi); -+ i = firstElement; -+ } -+ if (!multibootArgs) { -+ /* kernel args start after the -- */ -+ firstElement = i + 1; -+ } -+ } else if (cfg->cfi->mbConcatArgs) { -+ /* this is a non-multiboot entry, remove hyper args */ -+ for (i = firstElement; i < line->numElements; i++) { -+ if (!strcmp(line->elements[i].item, "--")) -+ break; -+ } -+ if (i < line->numElements) { -+ /* remove args up to -- */ -+ while (strcmp -+ (line->elements[firstElement].item, -+ "--")) -+ removeElement(line, firstElement); -+ /* remove -- */ -+ removeElement(line, firstElement); -+ } -+ } - -- return checkDeviceBootloader(line->elements[1].item, boot); --} -+ usedElements = calloc(line->numElements, sizeof(*usedElements)); - --int checkForGrub2(struct grubConfig * config) { -- if (!access("/etc/grub.d/", R_OK)) -- return 2; -+ for (k = 0, arg = newArgs; *arg; arg++, k++) { - -- return 1; --} -+ doreplace = 1; -+ for (i = firstElement; i < line->numElements; i++) { -+ if (multibootArgs && cfg->cfi->mbConcatArgs && -+ !strcmp(line->elements[i].item, "--")) { -+ /* reached the end of hyper args, insert here */ -+ doreplace = 0; -+ break; -+ } -+ if (usedElements[i]) -+ continue; -+ if (!argMatch(line->elements[i].item, *arg)) { -+ usedElements[i] = 1; -+ break; -+ } -+ } - --int checkForGrub(struct grubConfig * config) { -- int fd; -- unsigned char bootSect[512]; -- char * boot; -- int onSuse = isSuseSystem(); -+ if (i < line->numElements && doreplace) { -+ /* direct replacement */ -+ free(line->elements[i].item); -+ line->elements[i].item = strdup(*arg); -+ -+ } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) { -+ /* root= replacement */ -+ rootLine = getLineByType(LT_ROOT, entry->lines); -+ if (rootLine) { -+ free(rootLine->elements[1].item); -+ rootLine->elements[1].item = -+ strdup(*arg + 5); -+ } else { -+ rootLine = -+ addLine(entry, cfg->cfi, LT_ROOT, -+ cfg->secondaryIndent, -+ *arg + 5); -+ } -+ } - -+ else { -+ /* insert/append */ -+ insertElement(line, *arg, i, cfg->cfi); -+ usedElements = -+ realloc(usedElements, -+ line->numElements * -+ sizeof(*usedElements)); -+ memmove(&usedElements[i + 1], &usedElements[i], -+ line->numElements - i - 1); -+ usedElements[i] = 1; -+ -+ /* if we updated a root= here even though there is a -+ LT_ROOT available we need to remove the LT_ROOT entry -+ (this will happen if we switch from a device to a label) */ -+ if (useRoot && !strncmp(*arg, "root=", 5)) { -+ rootLine = -+ getLineByType(LT_ROOT, -+ entry->lines); -+ if (rootLine) -+ removeLine(entry, rootLine); -+ } -+ } -+ } - -- if (onSuse) { -- if (parseSuseGrubConf(NULL, &boot)) -- return 0; -- } else { -- if (parseSysconfigGrub(NULL, &boot)) -- return 0; -- } -+ free(usedElements); - -- /* assume grub is not installed -- not an error condition */ -- if (!boot) -- return 0; -+ for (arg = oldArgs; *arg; arg++) { -+ for (i = firstElement; i < line->numElements; i++) { -+ if (multibootArgs && cfg->cfi->mbConcatArgs && -+ !strcmp(line->elements[i].item, "--")) -+ /* reached the end of hyper args, stop here */ -+ break; -+ if (!argMatch(line->elements[i].item, *arg)) { -+ removeElement(line, i); -+ break; -+ } -+ } -+ /* handle removing LT_ROOT line too */ -+ if (useRoot && !strncmp(*arg, "root=", 5)) { -+ rootLine = getLineByType(LT_ROOT, entry->lines); -+ if (rootLine) -+ removeLine(entry, rootLine); -+ } -+ } - -- fd = open("/boot/grub/stage1", O_RDONLY); -- if (fd < 0) -- /* this doesn't exist if grub hasn't been installed */ -- return 0; -+ if (line->numElements == 1) { -+ /* don't need the line at all (note it has to be a -+ LT_KERNELARGS for this to happen */ -+ removeLine(entry, line); -+ } -+ } - -- if (read(fd, bootSect, 512) != 512) { -- fprintf(stderr, _("grubby: unable to read %s: %s\n"), -- "/boot/grub/stage1", strerror(errno)); -- close(fd); -- return 1; -- } -- close(fd); -+ free(newArgs); -+ free(oldArgs); - -- /* The more elaborate checks do not work on SuSE. The checks done -- * seem to be reasonble (at least for now), so just return success -- */ -- if (onSuse) -- return 2; -+ return 0; -+} - -- return checkDeviceBootloader(boot, bootSect); -+int updateImage(struct grubConfig *cfg, const char *image, -+ const char *prefix, const char *addArgs, -+ const char *removeArgs, -+ const char *addMBArgs, const char *removeMBArgs) -+{ -+ int rc = 0; -+ -+ if (!image) -+ return rc; -+ -+ /* update the main args first... */ -+ if (addArgs || removeArgs) -+ rc = updateActualImage(cfg, image, prefix, addArgs, removeArgs, -+ 0); -+ if (rc) -+ return rc; -+ -+ /* and now any multiboot args */ -+ if (addMBArgs || removeMBArgs) -+ rc = updateActualImage(cfg, image, prefix, addMBArgs, -+ removeMBArgs, 1); -+ return rc; - } - --int checkForExtLinux(struct grubConfig * config) { -- int fd; -- unsigned char bootSect[512]; -- char * boot; -- char executable[] = "/boot/extlinux/extlinux"; -+int addMBInitrd(struct grubConfig *cfg, const char *newMBKernel, -+ const char *image, const char *prefix, const char *initrd, -+ const char *title) -+{ -+ struct singleEntry *entry; -+ struct singleLine *line, *kernelLine, *endLine = NULL; -+ int index = 0; - -- printf("entered: checkForExtLinux()\n"); -+ if (!image) -+ return 0; - -- if (parseSysconfigGrub(NULL, &boot)) -- return 0; -+ for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); -+ index++) { -+ kernelLine = getLineByType(LT_MBMODULE, entry->lines); -+ if (!kernelLine) -+ continue; - -- /* assume grub is not installed -- not an error condition */ -- if (!boot) -- return 0; -+ /* if title is supplied, the entry's title must match it. */ -+ if (title) { -+ char *linetitle; -+ -+ line = -+ getLineByType(LT_TITLE | LT_MENUENTRY, -+ entry->lines); -+ if (!line) -+ continue; -+ -+ linetitle = extractTitle(cfg, line); -+ if (!linetitle) -+ continue; -+ if (strcmp(title, linetitle)) { -+ free(linetitle); -+ continue; -+ } -+ free(linetitle); -+ } - -- fd = open(executable, O_RDONLY); -- if (fd < 0) -- /* this doesn't exist if grub hasn't been installed */ -- return 0; -+ if (prefix) { -+ int prefixLen = strlen(prefix); -+ if (!strncmp(initrd, prefix, prefixLen)) -+ initrd += prefixLen; -+ } -+ endLine = getLineByType(LT_ENTRY_END, entry->lines); -+ if (endLine) -+ removeLine(entry, endLine); -+ line = -+ addLine(entry, cfg->cfi, -+ preferredLineType(LT_MBMODULE, cfg->cfi), -+ kernelLine->indent, initrd); -+ if (!line) -+ return 1; -+ if (endLine) { -+ line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); -+ if (!line) -+ return 1; -+ } - -- if (read(fd, bootSect, 512) != 512) { -- fprintf(stderr, _("grubby: unable to read %s: %s\n"), -- executable, strerror(errno)); -- return 1; -- } -- close(fd); -+ break; -+ } - -- return checkDeviceBootloader(boot, bootSect); -+ return 0; - } - --int checkForYaboot(struct grubConfig * config) { -- /* -- * This is a simplistic check that we consider good enough for own puporses -- * -- * If we were to properly check if yaboot is *installed* we'd need to: -- * 1) get the system boot device (LT_BOOT) -- * 2) considering it's a raw filesystem, check if the yaboot binary matches -- * the content on the boot device -- * 3) if not, copy the binary to a temporary file and run "addnote" on it -- * 4) check again if binary and boot device contents match -- */ -- if (!access("/etc/yaboot.conf", R_OK)) -- return 2; -- -- return 1; --} -+int updateInitrd(struct grubConfig *cfg, const char *image, -+ const char *prefix, const char *initrd, const char *title) -+{ -+ struct singleEntry *entry; -+ struct singleLine *line, *kernelLine, *endLine = NULL; -+ int index = 0; - --int checkForElilo(struct grubConfig * config) { -- if (!access("/etc/elilo.conf", R_OK)) -- return 2; -+ if (!image) -+ return 0; - -- return 1; --} -+ for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { -+ kernelLine = -+ getLineByType(LT_KERNEL | LT_KERNEL_EFI | LT_KERNEL_16, -+ entry->lines); -+ if (!kernelLine) -+ continue; - --static char * getRootSpecifier(char * str) { -- char * idx, * rootspec = NULL; -+ /* if title is supplied, the entry's title must match it. */ -+ if (title) { -+ char *linetitle; -+ -+ line = -+ getLineByType(LT_TITLE | LT_MENUENTRY, -+ entry->lines); -+ if (!line) -+ continue; -+ -+ linetitle = extractTitle(cfg, line); -+ if (!linetitle) -+ continue; -+ if (strcmp(title, linetitle)) { -+ free(linetitle); -+ continue; -+ } -+ free(linetitle); -+ } - -- if (*str == '(') { -- idx = rootspec = strdup(str); -- while(*idx && (*idx != ')') && (!isspace(*idx))) idx++; -- *(++idx) = '\0'; -- } -- return rootspec; -+ line = -+ getLineByType(LT_INITRD | LT_INITRD_EFI | LT_INITRD_16, -+ entry->lines); -+ if (line) -+ removeLine(entry, line); -+ if (prefix) { -+ int prefixLen = strlen(prefix); -+ if (!strncmp(initrd, prefix, prefixLen)) -+ initrd += prefixLen; -+ } -+ endLine = getLineByType(LT_ENTRY_END, entry->lines); -+ if (endLine) -+ removeLine(entry, endLine); -+ enum lineType_e lt; -+ switch (kernelLine->type) { -+ case LT_KERNEL: -+ lt = LT_INITRD; -+ break; -+ case LT_KERNEL_EFI: -+ lt = LT_INITRD_EFI; -+ break; -+ case LT_KERNEL_16: -+ lt = LT_INITRD_16; -+ break; -+ default: -+ lt = preferredLineType(LT_INITRD, cfg->cfi); -+ } -+ line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd); -+ if (!line) -+ return 1; -+ if (endLine) { -+ line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); -+ if (!line) -+ return 1; -+ } -+ -+ break; -+ } -+ -+ return 0; - } - --static char * getInitrdVal(struct grubConfig * config, -- const char * prefix, struct singleLine *tmplLine, -- const char * newKernelInitrd, -- const char ** extraInitrds, int extraInitrdCount) -+int checkDeviceBootloader(const char *device, const unsigned char *boot) - { -- char *initrdVal, *end; -- int i; -- size_t totalSize; -- size_t prefixLen; -- char separatorChar; -+ int fd; -+ unsigned char bootSect[512]; -+ int offset; -+ -+ fd = open(device, O_RDONLY); -+ if (fd < 0) { -+ fprintf(stderr, _("grubby: unable to open %s: %s\n"), -+ device, strerror(errno)); -+ return 1; -+ } - -- prefixLen = strlen(prefix); -- totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */; -+ if (read(fd, bootSect, 512) != 512) { -+ fprintf(stderr, _("grubby: unable to read %s: %s\n"), -+ device, strerror(errno)); -+ return 1; -+ } -+ close(fd); - -- for (i = 0; i < extraInitrdCount; i++) { -- totalSize += sizeof(separatorChar); -- totalSize += strlen(extraInitrds[i]) - prefixLen; -- } -+ /* first three bytes should match, a jmp short should be in there */ -+ if (memcmp(boot, bootSect, 3)) -+ return 0; - -- initrdVal = end = malloc(totalSize); -+ if (boot[1] == JMP_SHORT_OPCODE) { -+ offset = boot[2] + 2; -+ } else if (boot[1] == 0xe8 || boot[1] == 0xe9) { -+ offset = (boot[3] << 8) + boot[2] + 2; -+ } else if (boot[0] == JMP_SHORT_OPCODE) { -+ offset = boot[1] + 2; -+ /* -+ * it looks like grub, when copying stage1 into the mbr, patches stage1 -+ * right after the JMP location, replacing other instructions such as -+ * JMPs for NOOPs. So, relax the check a little bit by skipping those -+ * different bytes. -+ */ -+ if ((bootSect[offset + 1] == NOOP_OPCODE) -+ && (bootSect[offset + 2] == NOOP_OPCODE)) { -+ offset = offset + 3; -+ } -+ } else if (boot[0] == 0xe8 || boot[0] == 0xe9) { -+ offset = (boot[2] << 8) + boot[1] + 2; -+ } else { -+ return 0; -+ } - -- end = stpcpy (end, newKernelInitrd + prefixLen); -+ if (memcmp(boot + offset, bootSect + offset, CODE_SEG_SIZE)) -+ return 0; - -- separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar; -- for (i = 0; i < extraInitrdCount; i++) { -- const char *extraInitrd; -- int j; -+ return 2; -+} - -- extraInitrd = extraInitrds[i] + prefixLen; -- /* Don't add entries that are already there */ -- if (tmplLine != NULL) { -- for (j = 2; j < tmplLine->numElements; j++) -- if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0) -- break; -+int checkLiloOnRaid(char *mdDev, const unsigned char *boot) -+{ -+ int fd; -+ char buf[65536]; -+ char *end; -+ char *chptr; -+ char *chptr2; -+ int rc; -+ -+ /* it's on raid; we need to parse /proc/mdstat and check all of the -+ *raw* devices listed in there */ -+ -+ if (!strncmp(mdDev, "/dev/", 5)) -+ mdDev += 5; -+ -+ if ((fd = open("/proc/mdstat", O_RDONLY)) < 0) { -+ fprintf(stderr, _("grubby: failed to open /proc/mdstat: %s\n"), -+ strerror(errno)); -+ return 2; -+ } - -- if (j != tmplLine->numElements) -- continue; -+ rc = read(fd, buf, sizeof(buf) - 1); -+ if (rc < 0 || rc == (sizeof(buf) - 1)) { -+ fprintf(stderr, _("grubby: failed to read /proc/mdstat: %s\n"), -+ strerror(errno)); -+ close(fd); -+ return 2; - } -+ close(fd); -+ buf[rc] = '\0'; - -- *end++ = separatorChar; -- end = stpcpy(end, extraInitrd); -- } -+ chptr = buf; -+ while (*chptr) { -+ end = strchr(chptr, '\n'); -+ if (!end) -+ break; -+ *end = '\0'; -+ -+ if (!strncmp(chptr, mdDev, strlen(mdDev)) && -+ chptr[strlen(mdDev)] == ' ') { -+ -+ /* found the device */ -+ while (*chptr && *chptr != ':') -+ chptr++; -+ chptr++; -+ while (*chptr && isspace(*chptr)) -+ chptr++; -+ -+ /* skip the "active" bit */ -+ while (*chptr && !isspace(*chptr)) -+ chptr++; -+ while (*chptr && isspace(*chptr)) -+ chptr++; -+ -+ /* skip the raid level */ -+ while (*chptr && !isspace(*chptr)) -+ chptr++; -+ while (*chptr && isspace(*chptr)) -+ chptr++; -+ -+ /* everything else is partition stuff */ -+ while (*chptr) { -+ chptr2 = chptr; -+ while (*chptr2 && *chptr2 != '[') -+ chptr2++; -+ if (!*chptr2) -+ break; - -- return initrdVal; --} -+ /* yank off the numbers at the end */ -+ chptr2--; -+ while (isdigit(*chptr2) && chptr2 > chptr) -+ chptr2--; -+ chptr2++; -+ *chptr2 = '\0'; -+ -+ /* Better, now we need the /dev/ back. We're done with -+ * everything before this point, so we can just put -+ * the /dev/ part there. There will always be room. */ -+ memcpy(chptr - 5, "/dev/", 5); -+ rc = checkDeviceBootloader(chptr - 5, boot); -+ if (rc != 2) { -+ return rc; -+ } - --int addNewKernel(struct grubConfig * config, struct singleEntry * template, -- const char * prefix, -- const char * newKernelPath, const char * newKernelTitle, -- const char * newKernelArgs, const char * newKernelInitrd, -- const char ** extraInitrds, int extraInitrdCount, -- const char * newMBKernel, const char * newMBKernelArgs) { -- struct singleEntry * new; -- struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL; -- int needs; -- char * chptr; -- -- if (!newKernelPath) return 0; -- -- /* if the newKernelTitle is too long silently munge it into something -- * we can live with. truncating is first check, then we'll just mess with -- * it until it looks better */ -- if (config->cfi->maxTitleLength && -- (strlen(newKernelTitle) > config->cfi->maxTitleLength)) { -- char * buf = alloca(config->cfi->maxTitleLength + 7); -- char * numBuf = alloca(config->cfi->maxTitleLength + 1); -- int i = 1; -- -- sprintf(buf, "TITLE=%.*s", config->cfi->maxTitleLength, newKernelTitle); -- while (findEntryByPath(config, buf, NULL, NULL)) { -- sprintf(numBuf, "%d", i++); -- strcpy(buf + strlen(buf) - strlen(numBuf), numBuf); -- } -- -- newKernelTitle = buf + 6; -- } -- -- new = malloc(sizeof(*new)); -- new->skip = 0; -- new->multiboot = 0; -- new->next = config->entries; -- new->lines = NULL; -- config->entries = new; -- -- /* copy/update from the template */ -- needs = NEED_KERNEL | NEED_TITLE; -- if (newKernelInitrd) -- needs |= NEED_INITRD; -- if (newMBKernel) { -- needs |= NEED_MB; -- new->multiboot = 1; -- } -- -- if (template) { -- for (masterLine = template->lines; -- masterLine && (tmplLine = lineDup(masterLine)); -- lineFree(tmplLine), masterLine = masterLine->next) -- { -- dbgPrintf("addNewKernel processing %d\n", tmplLine->type); -- -- /* skip comments */ -- chptr = tmplLine->indent; -- while (*chptr && isspace(*chptr)) chptr++; -- if (*chptr == '#') continue; -- -- if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) { -- if (!template->multiboot && (needs & NEED_MB)) { -- /* it's not a multiboot template and this is the kernel -- * line. Try to be intelligent about inserting the -- * hypervisor at the same time. -- */ -- if (config->cfi->mbHyperFirst) { -- /* insert the hypervisor first */ -- newLine = addLine(new, config->cfi, LT_HYPER, -- tmplLine->indent, -- newMBKernel + strlen(prefix)); -- /* set up for adding the kernel line */ -- free(tmplLine->indent); -- tmplLine->indent = strdup(config->secondaryIndent); -- needs &= ~NEED_MB; -- } -- if (needs & NEED_KERNEL) { -- /* use addLineTmpl to preserve line elements, -- * otherwise we could just call addLine. Unfortunately -- * this means making some changes to the template -- * such as the indent change above and the type -- * change below. -- */ -- struct keywordTypes * mbm_kw = -- getKeywordByType(LT_MBMODULE, config->cfi); -- if (mbm_kw) { -- tmplLine->type = LT_MBMODULE; -- free(tmplLine->elements[0].item); -- tmplLine->elements[0].item = strdup(mbm_kw->key); -+ chptr = chptr2 + 1; -+ /* skip the [11] bit */ -+ while (*chptr && !isspace(*chptr)) -+ chptr++; -+ /* and move to the next one */ -+ while (*chptr && isspace(*chptr)) -+ chptr++; - } -- newLine = addLineTmpl(new, tmplLine, newLine, -- newKernelPath + strlen(prefix), config->cfi); -- needs &= ~NEED_KERNEL; -- } -- if (needs & NEED_MB) { /* !mbHyperFirst */ -- newLine = addLine(new, config->cfi, LT_HYPER, -- config->secondaryIndent, -- newMBKernel + strlen(prefix)); -- needs &= ~NEED_MB; -- } -- } else if (needs & NEED_KERNEL) { -- newLine = addLineTmpl(new, tmplLine, newLine, -- newKernelPath + strlen(prefix), config->cfi); -- needs &= ~NEED_KERNEL; -- } - -- } else if (tmplLine->type == LT_HYPER && -- tmplLine->numElements >= 2) { -- if (needs & NEED_MB) { -- newLine = addLineTmpl(new, tmplLine, newLine, -- newMBKernel + strlen(prefix), config->cfi); -- needs &= ~NEED_MB; -+ /* we're good to go */ -+ return 2; - } - -- } else if (tmplLine->type == LT_MBMODULE && -- tmplLine->numElements >= 2) { -- if (new->multiboot) { -- if (needs & NEED_KERNEL) { -- newLine = addLineTmpl(new, tmplLine, newLine, -- newKernelPath + -- strlen(prefix), config->cfi); -- needs &= ~NEED_KERNEL; -- } else if (config->cfi->mbInitRdIsModule && -- (needs & NEED_INITRD)) { -- char *initrdVal; -- initrdVal = getInitrdVal(config, prefix, tmplLine, -- newKernelInitrd, extraInitrds, -- extraInitrdCount); -- newLine = addLineTmpl(new, tmplLine, newLine, -- initrdVal, config->cfi); -- free(initrdVal); -- needs &= ~NEED_INITRD; -- } -- } else if (needs & NEED_KERNEL) { -- /* template is multi but new is not, -- * insert the kernel in the first module slot -- */ -- tmplLine->type = preferredLineType(LT_KERNEL, config->cfi); -- free(tmplLine->elements[0].item); -- tmplLine->elements[0].item = -- strdup(getKeywordByType(tmplLine->type, -- config->cfi)->key); -- newLine = addLineTmpl(new, tmplLine, newLine, -- newKernelPath + strlen(prefix), -- config->cfi); -- needs &= ~NEED_KERNEL; -- } else if (needs & NEED_INITRD) { -- char *initrdVal; -- /* template is multi but new is not, -- * insert the initrd in the second module slot -- */ -- tmplLine->type = preferredLineType(LT_INITRD, config->cfi); -- free(tmplLine->elements[0].item); -- tmplLine->elements[0].item = -- strdup(getKeywordByType(tmplLine->type, -- config->cfi)->key); -- initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount); -- newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi); -- free(initrdVal); -- needs &= ~NEED_INITRD; -- } -+ chptr = end + 1; -+ } -+ -+ fprintf(stderr, -+ _("grubby: raid device /dev/%s not found in /proc/mdstat\n"), -+ mdDev); -+ return 0; -+} -+ -+int checkForLilo(struct grubConfig *config) -+{ -+ int fd; -+ unsigned char boot[512]; -+ struct singleLine *line; -+ -+ for (line = config->theLines; line; line = line->next) -+ if (line->type == LT_BOOT) -+ break; -+ -+ if (!line) { -+ fprintf(stderr, -+ _ -+ ("grubby: no boot line found in lilo configuration\n")); -+ return 1; -+ } -+ -+ if (line->numElements != 2) -+ return 1; -+ -+ fd = open("/boot/boot.b", O_RDONLY); -+ if (fd < 0) { -+ fprintf(stderr, _("grubby: unable to open %s: %s\n"), -+ "/boot/boot.b", strerror(errno)); -+ return 1; -+ } -+ -+ if (read(fd, boot, 512) != 512) { -+ fprintf(stderr, _("grubby: unable to read %s: %s\n"), -+ "/boot/boot.b", strerror(errno)); -+ return 1; -+ } -+ close(fd); -+ -+ if (!strncmp("/dev/md", line->elements[1].item, 7)) -+ return checkLiloOnRaid(line->elements[1].item, boot); -+ -+ return checkDeviceBootloader(line->elements[1].item, boot); -+} -+ -+int checkForGrub2(struct grubConfig *config) -+{ -+ if (!access("/etc/grub.d/", R_OK)) -+ return 2; -+ -+ return 1; -+} -+ -+int checkForGrub(struct grubConfig *config) -+{ -+ int fd; -+ unsigned char bootSect[512]; -+ char *boot; -+ int onSuse = isSuseSystem(); -+ -+ if (onSuse) { -+ if (parseSuseGrubConf(NULL, &boot)) -+ return 0; -+ } else { -+ if (parseSysconfigGrub(NULL, &boot)) -+ return 0; -+ } -+ -+ /* assume grub is not installed -- not an error condition */ -+ if (!boot) -+ return 0; - -- } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) { -- if (needs & NEED_INITRD && -- new->multiboot && !template->multiboot && -- config->cfi->mbInitRdIsModule) { -- /* make sure we don't insert the module initrd -- * before the module kernel... if we don't do it here, -- * it will be inserted following the template. -- */ -- if (!needs & NEED_KERNEL) { -- char *initrdVal; -- -- initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount); -- newLine = addLine(new, config->cfi, LT_MBMODULE, -- config->secondaryIndent, -- initrdVal); -- free(initrdVal); -- needs &= ~NEED_INITRD; -- } -- } else if (needs & NEED_INITRD) { -- char *initrdVal; -- initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount); -- newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi); -- free(initrdVal); -- needs &= ~NEED_INITRD; -+ fd = open("/boot/grub/stage1", O_RDONLY); -+ if (fd < 0) -+ /* this doesn't exist if grub hasn't been installed */ -+ return 0; -+ -+ if (read(fd, bootSect, 512) != 512) { -+ fprintf(stderr, _("grubby: unable to read %s: %s\n"), -+ "/boot/grub/stage1", strerror(errno)); -+ close(fd); -+ return 1; -+ } -+ close(fd); -+ -+ /* The more elaborate checks do not work on SuSE. The checks done -+ * seem to be reasonble (at least for now), so just return success -+ */ -+ if (onSuse) -+ return 2; -+ -+ return checkDeviceBootloader(boot, bootSect); -+} -+ -+int checkForExtLinux(struct grubConfig *config) -+{ -+ int fd; -+ unsigned char bootSect[512]; -+ char *boot; -+ char executable[] = "/boot/extlinux/extlinux"; -+ -+ printf("entered: checkForExtLinux()\n"); -+ -+ if (parseSysconfigGrub(NULL, &boot)) -+ return 0; -+ -+ /* assume grub is not installed -- not an error condition */ -+ if (!boot) -+ return 0; -+ -+ fd = open(executable, O_RDONLY); -+ if (fd < 0) -+ /* this doesn't exist if grub hasn't been installed */ -+ return 0; -+ -+ if (read(fd, bootSect, 512) != 512) { -+ fprintf(stderr, _("grubby: unable to read %s: %s\n"), -+ executable, strerror(errno)); -+ return 1; -+ } -+ close(fd); -+ -+ return checkDeviceBootloader(boot, bootSect); -+} -+ -+int checkForYaboot(struct grubConfig *config) -+{ -+ /* -+ * This is a simplistic check that we consider good enough for own puporses -+ * -+ * If we were to properly check if yaboot is *installed* we'd need to: -+ * 1) get the system boot device (LT_BOOT) -+ * 2) considering it's a raw filesystem, check if the yaboot binary matches -+ * the content on the boot device -+ * 3) if not, copy the binary to a temporary file and run "addnote" on it -+ * 4) check again if binary and boot device contents match -+ */ -+ if (!access("/etc/yaboot.conf", R_OK)) -+ return 2; -+ -+ return 1; -+} -+ -+int checkForElilo(struct grubConfig *config) -+{ -+ if (!access("/etc/elilo.conf", R_OK)) -+ return 2; -+ -+ return 1; -+} -+ -+static char *getRootSpecifier(char *str) -+{ -+ char *idx, *rootspec = NULL; -+ -+ if (*str == '(') { -+ idx = rootspec = strdup(str); -+ while (*idx && (*idx != ')') && (!isspace(*idx))) -+ idx++; -+ *(++idx) = '\0'; -+ } -+ return rootspec; -+} -+ -+static char *getInitrdVal(struct grubConfig *config, -+ const char *prefix, struct singleLine *tmplLine, -+ const char *newKernelInitrd, -+ const char **extraInitrds, int extraInitrdCount) -+{ -+ char *initrdVal, *end; -+ int i; -+ size_t totalSize; -+ size_t prefixLen; -+ char separatorChar; -+ -+ prefixLen = strlen(prefix); -+ totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */ ; -+ -+ for (i = 0; i < extraInitrdCount; i++) { -+ totalSize += sizeof(separatorChar); -+ totalSize += strlen(extraInitrds[i]) - prefixLen; -+ } -+ -+ initrdVal = end = malloc(totalSize); -+ -+ end = stpcpy(end, newKernelInitrd + prefixLen); -+ -+ separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar; -+ for (i = 0; i < extraInitrdCount; i++) { -+ const char *extraInitrd; -+ int j; -+ -+ extraInitrd = extraInitrds[i] + prefixLen; -+ /* Don't add entries that are already there */ -+ if (tmplLine != NULL) { -+ for (j = 2; j < tmplLine->numElements; j++) -+ if (strcmp -+ (extraInitrd, -+ tmplLine->elements[j].item) == 0) -+ break; -+ -+ if (j != tmplLine->numElements) -+ continue; - } - -- } else if (tmplLine->type == LT_MENUENTRY && -- (needs & NEED_TITLE)) { -- requote(tmplLine, config->cfi); -- char *nkt = malloc(strlen(newKernelTitle)+3); -- strcpy(nkt, "'"); -- strcat(nkt, newKernelTitle); -- strcat(nkt, "'"); -- newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi); -- free(nkt); -- needs &= ~NEED_TITLE; -- } else if (tmplLine->type == LT_TITLE && -- (needs & NEED_TITLE)) { -- if (tmplLine->numElements >= 2) { -- newLine = addLineTmpl(new, tmplLine, newLine, -- newKernelTitle, config->cfi); -- needs &= ~NEED_TITLE; -- } else if (tmplLine->numElements == 1 && -- config->cfi->titleBracketed) { -- /* addLineTmpl doesn't handle titleBracketed */ -- newLine = addLine(new, config->cfi, LT_TITLE, -- tmplLine->indent, newKernelTitle); -- needs &= ~NEED_TITLE; -+ *end++ = separatorChar; -+ end = stpcpy(end, extraInitrd); -+ } -+ -+ return initrdVal; -+} -+ -+int addNewKernel(struct grubConfig *config, struct singleEntry *template, -+ const char *prefix, -+ const char *newKernelPath, const char *newKernelTitle, -+ const char *newKernelArgs, const char *newKernelInitrd, -+ const char **extraInitrds, int extraInitrdCount, -+ const char *newMBKernel, const char *newMBKernelArgs) -+{ -+ struct singleEntry *new; -+ struct singleLine *newLine = NULL, *tmplLine = NULL, *masterLine = NULL; -+ int needs; -+ char *chptr; -+ -+ if (!newKernelPath) -+ return 0; -+ -+ /* if the newKernelTitle is too long silently munge it into something -+ * we can live with. truncating is first check, then we'll just mess with -+ * it until it looks better */ -+ if (config->cfi->maxTitleLength && -+ (strlen(newKernelTitle) > config->cfi->maxTitleLength)) { -+ char *buf = alloca(config->cfi->maxTitleLength + 7); -+ char *numBuf = alloca(config->cfi->maxTitleLength + 1); -+ int i = 1; -+ -+ sprintf(buf, "TITLE=%.*s", config->cfi->maxTitleLength, -+ newKernelTitle); -+ while (findEntryByPath(config, buf, NULL, NULL)) { -+ sprintf(numBuf, "%d", i++); -+ strcpy(buf + strlen(buf) - strlen(numBuf), numBuf); - } -- } else if (tmplLine->type == LT_ECHO) { -- requote(tmplLine, config->cfi); -- static const char *prefix = "'Loading "; -- if (tmplLine->numElements > 1 && -- strstr(tmplLine->elements[1].item, prefix) && -- masterLine->next && -- iskernel(masterLine->next->type)) { -- char *newTitle = malloc(strlen(prefix) + -- strlen(newKernelTitle) + 2); -- -- strcpy(newTitle, prefix); -- strcat(newTitle, newKernelTitle); -- strcat(newTitle, "'"); -- newLine = addLine(new, config->cfi, LT_ECHO, -- tmplLine->indent, newTitle); -- free(newTitle); -- } else { -- /* pass through other lines from the template */ -- newLine = addLineTmpl(new, tmplLine, newLine, NULL, -- config->cfi); -- } -- } else { -- /* pass through other lines from the template */ -- newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi); -- } -+ -+ newKernelTitle = buf + 6; - } - -- } else { -- /* don't have a template, so start the entry with the -- * appropriate starting line -- */ -- switch (config->cfi->entryStart) { -- case LT_KERNEL: -- case LT_KERNEL_EFI: -- case LT_KERNEL_16: -- if (new->multiboot && config->cfi->mbHyperFirst) { -- /* fall through to LT_HYPER */ -- } else { -- newLine = addLine(new, config->cfi, -- preferredLineType(LT_KERNEL, config->cfi), -- config->primaryIndent, -- newKernelPath + strlen(prefix)); -- needs &= ~NEED_KERNEL; -- break; -+ new = malloc(sizeof(*new)); -+ new->skip = 0; -+ new->multiboot = 0; -+ new->next = config->entries; -+ new->lines = NULL; -+ config->entries = new; -+ -+ /* copy/update from the template */ -+ needs = NEED_KERNEL | NEED_TITLE; -+ if (newKernelInitrd) -+ needs |= NEED_INITRD; -+ if (newMBKernel) { -+ needs |= NEED_MB; -+ new->multiboot = 1; -+ } -+ -+ if (template) { -+ for (masterLine = template->lines; -+ masterLine && (tmplLine = lineDup(masterLine)); -+ lineFree(tmplLine), masterLine = masterLine->next) { -+ dbgPrintf("addNewKernel processing %d\n", -+ tmplLine->type); -+ -+ /* skip comments */ -+ chptr = tmplLine->indent; -+ while (*chptr && isspace(*chptr)) -+ chptr++; -+ if (*chptr == '#') -+ continue; -+ -+ if (iskernel(tmplLine->type) -+ && tmplLine->numElements >= 2) { -+ if (!template->multiboot && (needs & NEED_MB)) { -+ /* it's not a multiboot template and this is the kernel -+ * line. Try to be intelligent about inserting the -+ * hypervisor at the same time. -+ */ -+ if (config->cfi->mbHyperFirst) { -+ /* insert the hypervisor first */ -+ newLine = -+ addLine(new, config->cfi, -+ LT_HYPER, -+ tmplLine->indent, -+ newMBKernel + -+ strlen(prefix)); -+ /* set up for adding the kernel line */ -+ free(tmplLine->indent); -+ tmplLine->indent = -+ strdup(config-> -+ secondaryIndent); -+ needs &= ~NEED_MB; -+ } -+ if (needs & NEED_KERNEL) { -+ /* use addLineTmpl to preserve line elements, -+ * otherwise we could just call addLine. Unfortunately -+ * this means making some changes to the template -+ * such as the indent change above and the type -+ * change below. -+ */ -+ struct keywordTypes *mbm_kw = -+ getKeywordByType -+ (LT_MBMODULE, config->cfi); -+ if (mbm_kw) { -+ tmplLine->type = -+ LT_MBMODULE; -+ free(tmplLine-> -+ elements[0].item); -+ tmplLine->elements[0]. -+ item = -+ strdup(mbm_kw->key); -+ } -+ newLine = -+ addLineTmpl(new, tmplLine, -+ newLine, -+ newKernelPath + -+ strlen(prefix), -+ config->cfi); -+ needs &= ~NEED_KERNEL; -+ } -+ if (needs & NEED_MB) { /* !mbHyperFirst */ -+ newLine = -+ addLine(new, config->cfi, -+ LT_HYPER, -+ config-> -+ secondaryIndent, -+ newMBKernel + -+ strlen(prefix)); -+ needs &= ~NEED_MB; -+ } -+ } else if (needs & NEED_KERNEL) { -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, -+ newKernelPath + -+ strlen(prefix), -+ config->cfi); -+ needs &= ~NEED_KERNEL; -+ } -+ -+ } else if (tmplLine->type == LT_HYPER && -+ tmplLine->numElements >= 2) { -+ if (needs & NEED_MB) { -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, -+ newMBKernel + -+ strlen(prefix), -+ config->cfi); -+ needs &= ~NEED_MB; -+ } -+ -+ } else if (tmplLine->type == LT_MBMODULE && -+ tmplLine->numElements >= 2) { -+ if (new->multiboot) { -+ if (needs & NEED_KERNEL) { -+ newLine = -+ addLineTmpl(new, tmplLine, -+ newLine, -+ newKernelPath + -+ strlen(prefix), -+ config->cfi); -+ needs &= ~NEED_KERNEL; -+ } else if (config->cfi->mbInitRdIsModule -+ && (needs & NEED_INITRD)) { -+ char *initrdVal; -+ initrdVal = -+ getInitrdVal(config, prefix, -+ tmplLine, -+ newKernelInitrd, -+ extraInitrds, -+ extraInitrdCount); -+ newLine = -+ addLineTmpl(new, tmplLine, -+ newLine, -+ initrdVal, -+ config->cfi); -+ free(initrdVal); -+ needs &= ~NEED_INITRD; -+ } -+ } else if (needs & NEED_KERNEL) { -+ /* template is multi but new is not, -+ * insert the kernel in the first module slot -+ */ -+ tmplLine->type = -+ preferredLineType(LT_KERNEL, -+ config->cfi); -+ free(tmplLine->elements[0].item); -+ tmplLine->elements[0].item = -+ strdup(getKeywordByType -+ (tmplLine->type, -+ config->cfi)->key); -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, -+ newKernelPath + -+ strlen(prefix), -+ config->cfi); -+ needs &= ~NEED_KERNEL; -+ } else if (needs & NEED_INITRD) { -+ char *initrdVal; -+ /* template is multi but new is not, -+ * insert the initrd in the second module slot -+ */ -+ tmplLine->type = -+ preferredLineType(LT_INITRD, -+ config->cfi); -+ free(tmplLine->elements[0].item); -+ tmplLine->elements[0].item = -+ strdup(getKeywordByType -+ (tmplLine->type, -+ config->cfi)->key); -+ initrdVal = -+ getInitrdVal(config, prefix, -+ tmplLine, -+ newKernelInitrd, -+ extraInitrds, -+ extraInitrdCount); -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, -+ initrdVal, config->cfi); -+ free(initrdVal); -+ needs &= ~NEED_INITRD; -+ } -+ -+ } else if (isinitrd(tmplLine->type) -+ && tmplLine->numElements >= 2) { -+ if (needs & NEED_INITRD && new->multiboot -+ && !template->multiboot -+ && config->cfi->mbInitRdIsModule) { -+ /* make sure we don't insert the module initrd -+ * before the module kernel... if we don't do it here, -+ * it will be inserted following the template. -+ */ -+ if (!needs & NEED_KERNEL) { -+ char *initrdVal; -+ -+ initrdVal = -+ getInitrdVal(config, prefix, -+ tmplLine, -+ newKernelInitrd, -+ extraInitrds, -+ extraInitrdCount); -+ newLine = -+ addLine(new, config->cfi, -+ LT_MBMODULE, -+ config-> -+ secondaryIndent, -+ initrdVal); -+ free(initrdVal); -+ needs &= ~NEED_INITRD; -+ } -+ } else if (needs & NEED_INITRD) { -+ char *initrdVal; -+ initrdVal = -+ getInitrdVal(config, prefix, -+ tmplLine, -+ newKernelInitrd, -+ extraInitrds, -+ extraInitrdCount); -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, -+ initrdVal, config->cfi); -+ free(initrdVal); -+ needs &= ~NEED_INITRD; -+ } -+ -+ } else if (tmplLine->type == LT_MENUENTRY && -+ (needs & NEED_TITLE)) { -+ requote(tmplLine, config->cfi); -+ char *nkt = malloc(strlen(newKernelTitle) + 3); -+ strcpy(nkt, "'"); -+ strcat(nkt, newKernelTitle); -+ strcat(nkt, "'"); -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, nkt, -+ config->cfi); -+ free(nkt); -+ needs &= ~NEED_TITLE; -+ } else if (tmplLine->type == LT_TITLE && -+ (needs & NEED_TITLE)) { -+ if (tmplLine->numElements >= 2) { -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, -+ newKernelTitle, -+ config->cfi); -+ needs &= ~NEED_TITLE; -+ } else if (tmplLine->numElements == 1 && -+ config->cfi->titleBracketed) { -+ /* addLineTmpl doesn't handle titleBracketed */ -+ newLine = -+ addLine(new, config->cfi, LT_TITLE, -+ tmplLine->indent, -+ newKernelTitle); -+ needs &= ~NEED_TITLE; -+ } -+ } else if (tmplLine->type == LT_ECHO) { -+ requote(tmplLine, config->cfi); -+ static const char *prefix = "'Loading "; -+ if (tmplLine->numElements > 1 && -+ strstr(tmplLine->elements[1].item, prefix) -+ && masterLine->next -+ && iskernel(masterLine->next->type)) { -+ char *newTitle = -+ malloc(strlen(prefix) + -+ strlen(newKernelTitle) + 2); -+ -+ strcpy(newTitle, prefix); -+ strcat(newTitle, newKernelTitle); -+ strcat(newTitle, "'"); -+ newLine = -+ addLine(new, config->cfi, LT_ECHO, -+ tmplLine->indent, newTitle); -+ free(newTitle); -+ } else { -+ /* pass through other lines from the template */ -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, -+ NULL, config->cfi); -+ } -+ } else { -+ /* pass through other lines from the template */ -+ newLine = -+ addLineTmpl(new, tmplLine, newLine, NULL, -+ config->cfi); -+ } - } - -- case LT_HYPER: -- newLine = addLine(new, config->cfi, LT_HYPER, -- config->primaryIndent, -- newMBKernel + strlen(prefix)); -- needs &= ~NEED_MB; -- break; -+ } else { -+ /* don't have a template, so start the entry with the -+ * appropriate starting line -+ */ -+ switch (config->cfi->entryStart) { -+ case LT_KERNEL: -+ case LT_KERNEL_EFI: -+ case LT_KERNEL_16: -+ if (new->multiboot && config->cfi->mbHyperFirst) { -+ /* fall through to LT_HYPER */ -+ } else { -+ newLine = addLine(new, config->cfi, -+ preferredLineType(LT_KERNEL, -+ config-> -+ cfi), -+ config->primaryIndent, -+ newKernelPath + -+ strlen(prefix)); -+ needs &= ~NEED_KERNEL; -+ break; -+ } - -- case LT_MENUENTRY: { -- char *nkt = malloc(strlen(newKernelTitle)+3); -- strcpy(nkt, "'"); -- strcat(nkt, newKernelTitle); -- strcat(nkt, "'"); -- newLine = addLine(new, config->cfi, LT_MENUENTRY, -- config->primaryIndent, nkt); -- free(nkt); -- needs &= ~NEED_TITLE; -- needs |= NEED_END; -- break; -- } -- case LT_TITLE: -- if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above) -- char * templabel; -- int x = 0, y = 0; -- -- templabel = strdup(newKernelTitle); -- while( templabel[x]){ -- if( templabel[x] == ' ' ){ -- y = x; -- while( templabel[y] ){ -- templabel[y] = templabel[y+1]; -- y++; -+ case LT_HYPER: -+ newLine = addLine(new, config->cfi, LT_HYPER, -+ config->primaryIndent, -+ newMBKernel + strlen(prefix)); -+ needs &= ~NEED_MB; -+ break; -+ -+ case LT_MENUENTRY:{ -+ char *nkt = malloc(strlen(newKernelTitle) + 3); -+ strcpy(nkt, "'"); -+ strcat(nkt, newKernelTitle); -+ strcat(nkt, "'"); -+ newLine = -+ addLine(new, config->cfi, LT_MENUENTRY, -+ config->primaryIndent, nkt); -+ free(nkt); -+ needs &= ~NEED_TITLE; -+ needs |= NEED_END; -+ break; -+ } -+ case LT_TITLE: -+ if (useextlinuxmenu != 0) { // We just need useextlinuxmenu to not be zero (set above) -+ char *templabel; -+ int x = 0, y = 0; -+ -+ templabel = strdup(newKernelTitle); -+ while (templabel[x]) { -+ if (templabel[x] == ' ') { -+ y = x; -+ while (templabel[y]) { -+ templabel[y] = -+ templabel[y + 1]; -+ y++; -+ } - } -+ x++; - } -- x++; -+ newLine = addLine(new, config->cfi, LT_TITLE, -+ config->primaryIndent, -+ templabel); -+ free(templabel); -+ } else { -+ newLine = addLine(new, config->cfi, LT_TITLE, -+ config->primaryIndent, -+ newKernelTitle); - } -- newLine = addLine(new, config->cfi, LT_TITLE, -- config->primaryIndent, templabel); -- free(templabel); -- }else{ -- newLine = addLine(new, config->cfi, LT_TITLE, -- config->primaryIndent, newKernelTitle); -+ needs &= ~NEED_TITLE; -+ break; -+ -+ default: -+ abort(); - } -+ } -+ -+ struct singleLine *endLine = NULL; -+ endLine = getLineByType(LT_ENTRY_END, new->lines); -+ if (endLine) { -+ removeLine(new, endLine); -+ needs |= NEED_END; -+ } -+ -+ /* add the remainder of the lines, i.e. those that either -+ * weren't present in the template, or in the case of no template, -+ * all the lines following the entryStart. -+ */ -+ if (needs & NEED_TITLE) { -+ newLine = addLine(new, config->cfi, LT_TITLE, -+ config->secondaryIndent, newKernelTitle); - needs &= ~NEED_TITLE; -- break; -+ } -+ if ((needs & NEED_MB) && config->cfi->mbHyperFirst) { -+ newLine = addLine(new, config->cfi, LT_HYPER, -+ config->secondaryIndent, -+ newMBKernel + strlen(prefix)); -+ needs &= ~NEED_MB; -+ } -+ if (needs & NEED_KERNEL) { -+ newLine = addLine(new, config->cfi, -+ (new->multiboot -+ && getKeywordByType(LT_MBMODULE, -+ config->cfi)) -+ ? LT_MBMODULE : preferredLineType(LT_KERNEL, -+ config-> -+ cfi), -+ config->secondaryIndent, -+ newKernelPath + strlen(prefix)); -+ needs &= ~NEED_KERNEL; -+ } -+ if (needs & NEED_MB) { -+ newLine = addLine(new, config->cfi, LT_HYPER, -+ config->secondaryIndent, -+ newMBKernel + strlen(prefix)); -+ needs &= ~NEED_MB; -+ } -+ if (needs & NEED_INITRD) { -+ char *initrdVal; -+ initrdVal = -+ getInitrdVal(config, prefix, NULL, newKernelInitrd, -+ extraInitrds, extraInitrdCount); -+ newLine = -+ addLine(new, config->cfi, -+ (new->multiboot -+ && getKeywordByType(LT_MBMODULE, config->cfi)) -+ ? LT_MBMODULE : preferredLineType(LT_INITRD, -+ config->cfi), -+ config->secondaryIndent, initrdVal); -+ free(initrdVal); -+ needs &= ~NEED_INITRD; -+ } -+ if (needs & NEED_END) { -+ newLine = addLine(new, config->cfi, LT_ENTRY_END, -+ config->secondaryIndent, NULL); -+ needs &= ~NEED_END; -+ } - -- default: -+ if (needs) { -+ printf(_("grubby: needs=%d, aborting\n"), needs); - abort(); - } -- } -- -- struct singleLine *endLine = NULL; -- endLine = getLineByType(LT_ENTRY_END, new->lines); -- if (endLine) { -- removeLine(new, endLine); -- needs |= NEED_END; -- } -- -- /* add the remainder of the lines, i.e. those that either -- * weren't present in the template, or in the case of no template, -- * all the lines following the entryStart. -- */ -- if (needs & NEED_TITLE) { -- newLine = addLine(new, config->cfi, LT_TITLE, -- config->secondaryIndent, -- newKernelTitle); -- needs &= ~NEED_TITLE; -- } -- if ((needs & NEED_MB) && config->cfi->mbHyperFirst) { -- newLine = addLine(new, config->cfi, LT_HYPER, -- config->secondaryIndent, -- newMBKernel + strlen(prefix)); -- needs &= ~NEED_MB; -- } -- if (needs & NEED_KERNEL) { -- newLine = addLine(new, config->cfi, -- (new->multiboot && getKeywordByType(LT_MBMODULE, -- config->cfi)) -- ? LT_MBMODULE -- : preferredLineType(LT_KERNEL, config->cfi), -- config->secondaryIndent, -- newKernelPath + strlen(prefix)); -- needs &= ~NEED_KERNEL; -- } -- if (needs & NEED_MB) { -- newLine = addLine(new, config->cfi, LT_HYPER, -- config->secondaryIndent, -- newMBKernel + strlen(prefix)); -- needs &= ~NEED_MB; -- } -- if (needs & NEED_INITRD) { -- char *initrdVal; -- initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount); -- newLine = addLine(new, config->cfi, -- (new->multiboot && getKeywordByType(LT_MBMODULE, -- config->cfi)) -- ? LT_MBMODULE -- : preferredLineType(LT_INITRD, config->cfi), -- config->secondaryIndent, -- initrdVal); -- free(initrdVal); -- needs &= ~NEED_INITRD; -- } -- if (needs & NEED_END) { -- newLine = addLine(new, config->cfi, LT_ENTRY_END, -- config->secondaryIndent, NULL); -- needs &= ~NEED_END; -- } -- -- if (needs) { -- printf(_("grubby: needs=%d, aborting\n"), needs); -- abort(); -- } -- -- if (updateImage(config, "0", prefix, newKernelArgs, NULL, -- newMBKernelArgs, NULL)) return 1; -- -- return 0; -+ -+ if (updateImage(config, "0", prefix, newKernelArgs, NULL, -+ newMBKernelArgs, NULL)) -+ return 1; -+ -+ return 0; - } - --int main(int argc, const char ** argv) { -- poptContext optCon; -- const char * grubConfig = NULL; -- char * outputFile = NULL; -- int arg = 0; -- int flags = 0; -- int badImageOkay = 0; -- int configureGrub2 = 0; -- int configureLilo = 0, configureELilo = 0, configureGrub = 0; -- int configureYaboot = 0, configureSilo = 0, configureZipl = 0; -- int configureExtLinux = 0; -- int bootloaderProbe = 0; -- int extraInitrdCount = 0; -- char * updateKernelPath = NULL; -- char * newKernelPath = NULL; -- char * removeKernelPath = NULL; -- char * newKernelArgs = NULL; -- char * newKernelInitrd = NULL; -- char * newKernelTitle = NULL; -- char * newKernelVersion = NULL; -- char * newMBKernel = NULL; -- char * newMBKernelArgs = NULL; -- char * removeMBKernelArgs = NULL; -- char * removeMBKernel = NULL; -- char * bootPrefix = NULL; -- char * defaultKernel = NULL; -- char * removeArgs = NULL; -- char * kernelInfo = NULL; -- char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL }; -- char * envPath = NULL; -- const char * chptr = NULL; -- struct configFileInfo * cfi = NULL; -- struct grubConfig * config; -- struct singleEntry * template = NULL; -- int copyDefault = 0, makeDefault = 0; -- int displayDefault = 0; -- int displayDefaultIndex = 0; -- int displayDefaultTitle = 0; -- int defaultIndex = -1; -- struct poptOption options[] = { -- { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0, -- _("add an entry for the specified kernel"), _("kernel-path") }, -- { "add-multiboot", 0, POPT_ARG_STRING, &newMBKernel, 0, -- _("add an entry for the specified multiboot kernel"), NULL }, -- { "args", 0, POPT_ARG_STRING, &newKernelArgs, 0, -- _("default arguments for the new kernel or new arguments for " -- "kernel being updated"), _("args") }, -- { "mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0, -- _("default arguments for the new multiboot kernel or " -- "new arguments for multiboot kernel being updated"), NULL }, -- { "bad-image-okay", 0, 0, &badImageOkay, 0, -- _("don't sanity check images in boot entries (for testing only)"), -- NULL }, -- { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0, -- _("filestystem which contains /boot directory (for testing only)"), -- _("bootfs") }, -+int main(int argc, const char **argv) -+{ -+ poptContext optCon; -+ const char *grubConfig = NULL; -+ char *outputFile = NULL; -+ int arg = 0; -+ int flags = 0; -+ int badImageOkay = 0; -+ int configureGrub2 = 0; -+ int configureLilo = 0, configureELilo = 0, configureGrub = 0; -+ int configureYaboot = 0, configureSilo = 0, configureZipl = 0; -+ int configureExtLinux = 0; -+ int bootloaderProbe = 0; -+ int extraInitrdCount = 0; -+ char *updateKernelPath = NULL; -+ char *newKernelPath = NULL; -+ char *removeKernelPath = NULL; -+ char *newKernelArgs = NULL; -+ char *newKernelInitrd = NULL; -+ char *newKernelTitle = NULL; -+ char *newKernelVersion = NULL; -+ char *newMBKernel = NULL; -+ char *newMBKernelArgs = NULL; -+ char *removeMBKernelArgs = NULL; -+ char *removeMBKernel = NULL; -+ char *bootPrefix = NULL; -+ char *defaultKernel = NULL; -+ char *removeArgs = NULL; -+ char *kernelInfo = NULL; -+ char *extraInitrds[MAX_EXTRA_INITRDS] = { NULL }; -+ char *envPath = NULL; -+ const char *chptr = NULL; -+ struct configFileInfo *cfi = NULL; -+ struct grubConfig *config; -+ struct singleEntry *template = NULL; -+ int copyDefault = 0, makeDefault = 0; -+ int displayDefault = 0; -+ int displayDefaultIndex = 0; -+ int displayDefaultTitle = 0; -+ int defaultIndex = -1; -+ struct poptOption options[] = { -+ {"add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0, -+ _("add an entry for the specified kernel"), _("kernel-path")}, -+ {"add-multiboot", 0, POPT_ARG_STRING, &newMBKernel, 0, -+ _("add an entry for the specified multiboot kernel"), NULL}, -+ {"args", 0, POPT_ARG_STRING, &newKernelArgs, 0, -+ _("default arguments for the new kernel or new arguments for " -+ "kernel being updated"), _("args")}, -+ {"mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0, -+ _("default arguments for the new multiboot kernel or " -+ "new arguments for multiboot kernel being updated"), NULL}, -+ {"bad-image-okay", 0, 0, &badImageOkay, 0, -+ _ -+ ("don't sanity check images in boot entries (for testing only)"), -+ NULL}, -+ {"boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0, -+ _ -+ ("filestystem which contains /boot directory (for testing only)"), -+ _("bootfs")}, - #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__) -- { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0, -- _("check which bootloader is installed on boot sector") }, -+ {"bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0, -+ _("check which bootloader is installed on boot sector")}, - #endif -- { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0, -- _("path to grub config file to update (\"-\" for stdin)"), -- _("path") }, -- { "copy-default", 0, 0, ©Default, 0, -- _("use the default boot entry as a template for the new entry " -- "being added; if the default is not a linux image, or if " -- "the kernel referenced by the default image does not exist, " -- "the first linux entry whose kernel does exist is used as the " -- "template"), NULL }, -- { "debug", 0, 0, &debug, 0, -- _("print debugging information for failures") }, -- { "default-kernel", 0, 0, &displayDefault, 0, -- _("display the path of the default kernel") }, -- { "default-index", 0, 0, &displayDefaultIndex, 0, -- _("display the index of the default kernel") }, -- { "default-title", 0, 0, &displayDefaultTitle, 0, -- _("display the title of the default kernel") }, -- { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0, -- _("configure elilo bootloader") }, -- { "efi", 0, POPT_ARG_NONE, &isEfi, 0, -- _("force grub2 stanzas to use efi") }, -- { "env", 0, POPT_ARG_STRING, &envPath, 0, -- _("path for environment data"), -- _("path") }, -- { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0, -- _("configure extlinux bootloader (from syslinux)") }, -- { "grub", 0, POPT_ARG_NONE, &configureGrub, 0, -- _("configure grub bootloader") }, -- { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0, -- _("configure grub2 bootloader") }, -- { "info", 0, POPT_ARG_STRING, &kernelInfo, 0, -- _("display boot information for specified kernel"), -- _("kernel-path") }, -- { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0, -- _("initrd image for the new kernel"), _("initrd-path") }, -- { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i', -- _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") }, -- { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0, -- _("configure lilo bootloader") }, -- { "make-default", 0, 0, &makeDefault, 0, -- _("make the newly added entry the default boot entry"), NULL }, -- { "output-file", 'o', POPT_ARG_STRING, &outputFile, 0, -- _("path to output updated config file (\"-\" for stdout)"), -- _("path") }, -- { "remove-args", 0, POPT_ARG_STRING, &removeArgs, 0, -- _("remove kernel arguments"), NULL }, -- { "remove-mbargs", 0, POPT_ARG_STRING, &removeMBKernelArgs, 0, -- _("remove multiboot kernel arguments"), NULL }, -- { "remove-kernel", 0, POPT_ARG_STRING, &removeKernelPath, 0, -- _("remove all entries for the specified kernel"), -- _("kernel-path") }, -- { "remove-multiboot", 0, POPT_ARG_STRING, &removeMBKernel, 0, -- _("remove all entries for the specified multiboot kernel"), NULL }, -- { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0, -- _("make the first entry referencing the specified kernel " -- "the default"), _("kernel-path") }, -- { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0, -- _("make the given entry index the default entry"), -- _("entry-index") }, -- { "silo", 0, POPT_ARG_NONE, &configureSilo, 0, -- _("configure silo bootloader") }, -- { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0, -- _("title to use for the new kernel entry"), _("entry-title") }, -- { "update-kernel", 0, POPT_ARG_STRING, &updateKernelPath, 0, -- _("updated information for the specified kernel"), -- _("kernel-path") }, -- { "version", 'v', 0, NULL, 'v', -- _("print the version of this program and exit"), NULL }, -- { "yaboot", 0, POPT_ARG_NONE, &configureYaboot, 0, -- _("configure yaboot bootloader") }, -- { "zipl", 0, POPT_ARG_NONE, &configureZipl, 0, -- _("configure zipl bootloader") }, -- POPT_AUTOHELP -- { 0, 0, 0, 0, 0 } -- }; -- -- useextlinuxmenu=0; -- -- int i = 0; -- for (int j = 1; j < argc; j++) -- i += strlen(argv[j]) + 1; -- saved_command_line = malloc(i); -- if (!saved_command_line) { -- fprintf(stderr, "grubby: %m\n"); -- exit(1); -- } -- saved_command_line[0] = '\0'; -- for (int j = 1; j < argc; j++) { -- strcat(saved_command_line, argv[j]); -- strncat(saved_command_line, j == argc -1 ? "" : " ", 1); -- } -- -- optCon = poptGetContext("grubby", argc, argv, options, 0); -- poptReadDefaultConfig(optCon, 1); -- -- while ((arg = poptGetNextOpt(optCon)) >= 0) { -- switch (arg) { -- case 'v': -- printf("grubby version %s\n", VERSION); -- exit(0); -- break; -- case 'i': -- if (extraInitrdCount < MAX_EXTRA_INITRDS) { -- extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon)); -- } else { -- fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount); -+ {"config-file", 'c', POPT_ARG_STRING, &grubConfig, 0, -+ _("path to grub config file to update (\"-\" for stdin)"), -+ _("path")}, -+ {"copy-default", 0, 0, ©Default, 0, -+ _("use the default boot entry as a template for the new entry " -+ "being added; if the default is not a linux image, or if " -+ "the kernel referenced by the default image does not exist, " -+ "the first linux entry whose kernel does exist is used as the " -+ "template"), NULL}, -+ {"debug", 0, 0, &debug, 0, -+ _("print debugging information for failures")}, -+ {"default-kernel", 0, 0, &displayDefault, 0, -+ _("display the path of the default kernel")}, -+ {"default-index", 0, 0, &displayDefaultIndex, 0, -+ _("display the index of the default kernel")}, -+ {"default-title", 0, 0, &displayDefaultTitle, 0, -+ _("display the title of the default kernel")}, -+ {"elilo", 0, POPT_ARG_NONE, &configureELilo, 0, -+ _("configure elilo bootloader")}, -+ {"efi", 0, POPT_ARG_NONE, &isEfi, 0, -+ _("force grub2 stanzas to use efi")}, -+ {"env", 0, POPT_ARG_STRING, &envPath, 0, -+ _("path for environment data"), -+ _("path")}, -+ {"extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0, -+ _("configure extlinux bootloader (from syslinux)")}, -+ {"grub", 0, POPT_ARG_NONE, &configureGrub, 0, -+ _("configure grub bootloader")}, -+ {"grub2", 0, POPT_ARG_NONE, &configureGrub2, 0, -+ _("configure grub2 bootloader")}, -+ {"info", 0, POPT_ARG_STRING, &kernelInfo, 0, -+ _("display boot information for specified kernel"), -+ _("kernel-path")}, -+ {"initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0, -+ _("initrd image for the new kernel"), _("initrd-path")}, -+ {"extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i', -+ _ -+ ("auxiliary initrd image for things other than the new kernel"), -+ _("initrd-path")}, -+ {"lilo", 0, POPT_ARG_NONE, &configureLilo, 0, -+ _("configure lilo bootloader")}, -+ {"make-default", 0, 0, &makeDefault, 0, -+ _("make the newly added entry the default boot entry"), NULL}, -+ {"output-file", 'o', POPT_ARG_STRING, &outputFile, 0, -+ _("path to output updated config file (\"-\" for stdout)"), -+ _("path")}, -+ {"remove-args", 0, POPT_ARG_STRING, &removeArgs, 0, -+ _("remove kernel arguments"), NULL}, -+ {"remove-mbargs", 0, POPT_ARG_STRING, &removeMBKernelArgs, 0, -+ _("remove multiboot kernel arguments"), NULL}, -+ {"remove-kernel", 0, POPT_ARG_STRING, &removeKernelPath, 0, -+ _("remove all entries for the specified kernel"), -+ _("kernel-path")}, -+ {"remove-multiboot", 0, POPT_ARG_STRING, &removeMBKernel, 0, -+ _("remove all entries for the specified multiboot kernel"), -+ NULL}, -+ {"set-default", 0, POPT_ARG_STRING, &defaultKernel, 0, -+ _("make the first entry referencing the specified kernel " -+ "the default"), _("kernel-path")}, -+ {"set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0, -+ _("make the given entry index the default entry"), -+ _("entry-index")}, -+ {"silo", 0, POPT_ARG_NONE, &configureSilo, 0, -+ _("configure silo bootloader")}, -+ {"title", 0, POPT_ARG_STRING, &newKernelTitle, 0, -+ _("title to use for the new kernel entry"), _("entry-title")}, -+ {"update-kernel", 0, POPT_ARG_STRING, &updateKernelPath, 0, -+ _("updated information for the specified kernel"), -+ _("kernel-path")}, -+ {"version", 'v', 0, NULL, 'v', -+ _("print the version of this program and exit"), NULL}, -+ {"yaboot", 0, POPT_ARG_NONE, &configureYaboot, 0, -+ _("configure yaboot bootloader")}, -+ {"zipl", 0, POPT_ARG_NONE, &configureZipl, 0, -+ _("configure zipl bootloader")}, -+ POPT_AUTOHELP {0, 0, 0, 0, 0} -+ }; -+ -+ useextlinuxmenu = 0; -+ -+ int i = 0; -+ for (int j = 1; j < argc; j++) -+ i += strlen(argv[j]) + 1; -+ saved_command_line = malloc(i); -+ if (!saved_command_line) { -+ fprintf(stderr, "grubby: %m\n"); -+ exit(1); -+ } -+ saved_command_line[0] = '\0'; -+ for (int j = 1; j < argc; j++) { -+ strcat(saved_command_line, argv[j]); -+ strncat(saved_command_line, j == argc - 1 ? "" : " ", 1); -+ } -+ -+ optCon = poptGetContext("grubby", argc, argv, options, 0); -+ poptReadDefaultConfig(optCon, 1); -+ -+ while ((arg = poptGetNextOpt(optCon)) >= 0) { -+ switch (arg) { -+ case 'v': -+ printf("grubby version %s\n", VERSION); -+ exit(0); -+ break; -+ case 'i': -+ if (extraInitrdCount < MAX_EXTRA_INITRDS) { -+ extraInitrds[extraInitrdCount++] = -+ strdup(poptGetOptArg(optCon)); -+ } else { -+ fprintf(stderr, -+ _ -+ ("grubby: extra initrd maximum is %d\n"), -+ extraInitrdCount); -+ return 1; -+ } -+ break; -+ } -+ } -+ -+ if (arg < -1) { -+ fprintf(stderr, _("grubby: bad argument %s: %s\n"), -+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS), -+ poptStrerror(arg)); - return 1; -- } -- break; - } -- } - -- if (arg < -1) { -- fprintf(stderr, _("grubby: bad argument %s: %s\n"), -- poptBadOption(optCon, POPT_BADOPTION_NOALIAS), -- poptStrerror(arg)); -- return 1; -- } -+ if ((chptr = poptGetArg(optCon))) { -+ fprintf(stderr, _("grubby: unexpected argument %s\n"), chptr); -+ return 1; -+ } - -- if ((chptr = poptGetArg(optCon))) { -- fprintf(stderr, _("grubby: unexpected argument %s\n"), chptr); -- return 1; -- } -+ if ((configureLilo + configureGrub2 + configureGrub + configureELilo + -+ configureYaboot + configureSilo + configureZipl + -+ configureExtLinux) > 1) { -+ fprintf(stderr, -+ _("grubby: cannot specify multiple bootloaders\n")); -+ return 1; -+ } else if (bootloaderProbe && grubConfig) { -+ fprintf(stderr, -+ _ -+ ("grubby: cannot specify config file with --bootloader-probe\n")); -+ return 1; -+ } else if (configureGrub2) { -+ cfi = &grub2ConfigType; -+ if (envPath) -+ cfi->envFile = envPath; -+ } else if (configureLilo) { -+ cfi = &liloConfigType; -+ } else if (configureGrub) { -+ cfi = &grubConfigType; -+ } else if (configureELilo) { -+ cfi = &eliloConfigType; -+ } else if (configureYaboot) { -+ cfi = &yabootConfigType; -+ } else if (configureSilo) { -+ cfi = &siloConfigType; -+ } else if (configureZipl) { -+ cfi = &ziplConfigType; -+ } else if (configureExtLinux) { -+ cfi = &extlinuxConfigType; -+ useextlinuxmenu = 1; -+ } - -- if ((configureLilo + configureGrub2 + configureGrub + configureELilo + -- configureYaboot + configureSilo + configureZipl + -- configureExtLinux ) > 1) { -- fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n")); -- return 1; -- } else if (bootloaderProbe && grubConfig) { -- fprintf(stderr, -- _("grubby: cannot specify config file with --bootloader-probe\n")); -- return 1; -- } else if (configureGrub2) { -- cfi = &grub2ConfigType; -- if (envPath) -- cfi->envFile = envPath; -- } else if (configureLilo) { -- cfi = &liloConfigType; -- } else if (configureGrub) { -- cfi = &grubConfigType; -- } else if (configureELilo) { -- cfi = &eliloConfigType; -- } else if (configureYaboot) { -- cfi = &yabootConfigType; -- } else if (configureSilo) { -- cfi = &siloConfigType; -- } else if (configureZipl) { -- cfi = &ziplConfigType; -- } else if (configureExtLinux) { -- cfi = &extlinuxConfigType; -- useextlinuxmenu=1; -- } -- -- if (!cfi) { -- if (grub2FindConfig(&grub2ConfigType)) { -- cfi = &grub2ConfigType; -- if (envPath) -- cfi->envFile = envPath; -- } else -- #ifdef __ia64__ -- cfi = &eliloConfigType; -- #elif __powerpc__ -- cfi = &yabootConfigType; -- #elif __sparc__ -- cfi = &siloConfigType; -- #elif __s390__ -- cfi = &ziplConfigType; -- #elif __s390x__ -- cfi = &ziplConfigtype; -- #else -- cfi = &grubConfigType; -- #endif -- } -- -- if (!grubConfig) { -- if (cfi->findConfig) -- grubConfig = cfi->findConfig(cfi); -- if (!grubConfig) -- grubConfig = cfi->defaultConfig; -- } -- -- if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion || -- newKernelPath || removeKernelPath || makeDefault || -- defaultKernel || displayDefaultIndex || displayDefaultTitle || -- (defaultIndex >= 0))) { -- fprintf(stderr, _("grubby: --bootloader-probe may not be used with " -+ if (!cfi) { -+ if (grub2FindConfig(&grub2ConfigType)) { -+ cfi = &grub2ConfigType; -+ if (envPath) -+ cfi->envFile = envPath; -+ } else -+#ifdef __ia64__ -+ cfi = &eliloConfigType; -+#elif __powerpc__ -+ cfi = &yabootConfigType; -+#elif __sparc__ -+ cfi = &siloConfigType; -+#elif __s390__ -+ cfi = &ziplConfigType; -+#elif __s390x__ -+ cfi = &ziplConfigtype; -+#else -+ cfi = &grubConfigType; -+#endif -+ } -+ -+ if (!grubConfig) { -+ if (cfi->findConfig) -+ grubConfig = cfi->findConfig(cfi); -+ if (!grubConfig) -+ grubConfig = cfi->defaultConfig; -+ } -+ -+ if (bootloaderProbe -+ && (displayDefault || kernelInfo || newKernelVersion -+ || newKernelPath || removeKernelPath || makeDefault -+ || defaultKernel || displayDefaultIndex || displayDefaultTitle -+ || (defaultIndex >= 0))) { -+ fprintf(stderr, -+ _("grubby: --bootloader-probe may not be used with " - "specified option")); -- return 1; -- } -+ return 1; -+ } - -- if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath || -- removeKernelPath)) { -- fprintf(stderr, _("grubby: --default-kernel and --info may not " -+ if ((displayDefault || kernelInfo) -+ && (newKernelVersion || newKernelPath || removeKernelPath)) { -+ fprintf(stderr, -+ _("grubby: --default-kernel and --info may not " - "be used when adding or removing kernels\n")); -- return 1; -- } -+ return 1; -+ } - -- if (newKernelPath && !newKernelTitle) { -- fprintf(stderr, _("grubby: kernel title must be specified\n")); -- return 1; -- } else if (!newKernelPath && (copyDefault || -- (newKernelInitrd && !updateKernelPath)|| -- makeDefault || extraInitrdCount > 0)) { -- fprintf(stderr, _("grubby: kernel path expected\n")); -- return 1; -- } -+ if (newKernelPath && !newKernelTitle) { -+ fprintf(stderr, _("grubby: kernel title must be specified\n")); -+ return 1; -+ } else if (!newKernelPath && (copyDefault || -+ (newKernelInitrd && !updateKernelPath) || -+ makeDefault || extraInitrdCount > 0)) { -+ fprintf(stderr, _("grubby: kernel path expected\n")); -+ return 1; -+ } - -- if (newKernelPath && updateKernelPath) { -- fprintf(stderr, _("grubby: --add-kernel and --update-kernel may" -- "not be used together")); -- return 1; -- } -+ if (newKernelPath && updateKernelPath) { -+ fprintf(stderr, _("grubby: --add-kernel and --update-kernel may" -+ "not be used together")); -+ return 1; -+ } - -- if (makeDefault && defaultKernel) { -- fprintf(stderr, _("grubby: --make-default and --default-kernel " -- "may not be used together\n")); -- return 1; -- } else if (defaultKernel && removeKernelPath && -- !strcmp(defaultKernel, removeKernelPath)) { -- fprintf(stderr, _("grubby: cannot make removed kernel the default\n")); -- return 1; -- } else if (defaultKernel && newKernelPath && -- !strcmp(defaultKernel, newKernelPath)) { -- makeDefault = 1; -- defaultKernel = NULL; -- } -- else if (defaultKernel && (defaultIndex >= 0)) { -- fprintf(stderr, _("grubby: --set-default and --set-default-index " -+ if (makeDefault && defaultKernel) { -+ fprintf(stderr, _("grubby: --make-default and --default-kernel " -+ "may not be used together\n")); -+ return 1; -+ } else if (defaultKernel && removeKernelPath && -+ !strcmp(defaultKernel, removeKernelPath)) { -+ fprintf(stderr, -+ _("grubby: cannot make removed kernel the default\n")); -+ return 1; -+ } else if (defaultKernel && newKernelPath && -+ !strcmp(defaultKernel, newKernelPath)) { -+ makeDefault = 1; -+ defaultKernel = NULL; -+ } else if (defaultKernel && (defaultIndex >= 0)) { -+ fprintf(stderr, -+ _("grubby: --set-default and --set-default-index " - "may not be used together\n")); -- return 1; -- } -+ return 1; -+ } - -- if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) { -- fprintf(stderr, _("grubby: output file must be specified if stdin " -- "is used\n")); -- return 1; -- } -+ if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) { -+ fprintf(stderr, -+ _("grubby: output file must be specified if stdin " -+ "is used\n")); -+ return 1; -+ } - -- if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel -- && !kernelInfo && !bootloaderProbe && !updateKernelPath -- && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle -- && (defaultIndex == -1)) { -- fprintf(stderr, _("grubby: no action specified\n")); -- return 1; -- } -+ if (!removeKernelPath && !newKernelPath && !displayDefault -+ && !defaultKernel && !kernelInfo && !bootloaderProbe -+ && !updateKernelPath && !removeMBKernel && !displayDefaultIndex -+ && !displayDefaultTitle && (defaultIndex == -1)) { -+ fprintf(stderr, _("grubby: no action specified\n")); -+ return 1; -+ } - -- flags |= badImageOkay ? GRUBBY_BADIMAGE_OKAY : 0; -+ flags |= badImageOkay ? GRUBBY_BADIMAGE_OKAY : 0; - -- if (cfi->needsBootPrefix) { -- if (!bootPrefix) { -- bootPrefix = findBootPrefix(); -- if (!bootPrefix) return 1; -+ if (cfi->needsBootPrefix) { -+ if (!bootPrefix) { -+ bootPrefix = findBootPrefix(); -+ if (!bootPrefix) -+ return 1; -+ } else { -+ /* this shouldn't end with a / */ -+ if (bootPrefix[strlen(bootPrefix) - 1] == '/') -+ bootPrefix[strlen(bootPrefix) - 1] = '\0'; -+ } - } else { -- /* this shouldn't end with a / */ -- if (bootPrefix[strlen(bootPrefix) - 1] == '/') -- bootPrefix[strlen(bootPrefix) - 1] = '\0'; -+ bootPrefix = ""; - } -- } else { -- bootPrefix = ""; -- } -- -- if (!cfi->mbAllowExtraInitRds && -- extraInitrdCount > 0) { -- fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig); -- return 1; -- } -- -- if (bootloaderProbe) { -- int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0; -- struct grubConfig * lconfig, * gconfig, * yconfig, * econfig; -- -- const char *grub2config = grub2FindConfig(&grub2ConfigType); -- if (grub2config) { -- gconfig = readConfig(grub2config, &grub2ConfigType); -- if (!gconfig) -- gr2c = 1; -- else -- gr2c = checkForGrub2(gconfig); -- } -- -- const char *grubconfig = grubFindConfig(&grubConfigType); -- if (!access(grubconfig, F_OK)) { -- gconfig = readConfig(grubconfig, &grubConfigType); -- if (!gconfig) -- grc = 1; -- else -- grc = checkForGrub(gconfig); -- } -- -- if (!access(liloConfigType.defaultConfig, F_OK)) { -- lconfig = readConfig(liloConfigType.defaultConfig, &liloConfigType); -- if (!lconfig) -- lrc = 1; -- else -- lrc = checkForLilo(lconfig); -- } -- -- if (!access(eliloConfigType.defaultConfig, F_OK)) { -- econfig = readConfig(eliloConfigType.defaultConfig, -- &eliloConfigType); -- if (!econfig) -- erc = 1; -- else -- erc = checkForElilo(econfig); -- } -- -- if (!access(extlinuxConfigType.defaultConfig, F_OK)) { -- lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType); -- if (!lconfig) -- extrc = 1; -- else -- extrc = checkForExtLinux(lconfig); -- } -- -- -- if (!access(yabootConfigType.defaultConfig, F_OK)) { -- yconfig = readConfig(yabootConfigType.defaultConfig, -- &yabootConfigType); -- if (!yconfig) -- yrc = 1; -- else -- yrc = checkForYaboot(yconfig); -- } -- -- if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 || -- erc == 1) -- return 1; -- -- if (lrc == 2) printf("lilo\n"); -- if (gr2c == 2) printf("grub2\n"); -- if (grc == 2) printf("grub\n"); -- if (extrc == 2) printf("extlinux\n"); -- if (yrc == 2) printf("yaboot\n"); -- if (erc == 2) printf("elilo\n"); - -- return 0; -- } -+ if (!cfi->mbAllowExtraInitRds && extraInitrdCount > 0) { -+ fprintf(stderr, -+ _("grubby: %s doesn't allow multiple initrds\n"), -+ cfi->defaultConfig); -+ return 1; -+ } - -- if (grubConfig == NULL) { -- printf("Could not find bootloader configuration file.\n"); -- exit(1); -- } -+ if (bootloaderProbe) { -+ int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0; -+ struct grubConfig *lconfig, *gconfig, *yconfig, *econfig; -+ -+ const char *grub2config = grub2FindConfig(&grub2ConfigType); -+ if (grub2config) { -+ gconfig = readConfig(grub2config, &grub2ConfigType); -+ if (!gconfig) -+ gr2c = 1; -+ else -+ gr2c = checkForGrub2(gconfig); -+ } - -- config = readConfig(grubConfig, cfi); -- if (!config) return 1; -+ const char *grubconfig = grubFindConfig(&grubConfigType); -+ if (!access(grubconfig, F_OK)) { -+ gconfig = readConfig(grubconfig, &grubConfigType); -+ if (!gconfig) -+ grc = 1; -+ else -+ grc = checkForGrub(gconfig); -+ } - -- if (displayDefault) { -- struct singleLine * line; -- struct singleEntry * entry; -- char * rootspec; -+ if (!access(liloConfigType.defaultConfig, F_OK)) { -+ lconfig = -+ readConfig(liloConfigType.defaultConfig, -+ &liloConfigType); -+ if (!lconfig) -+ lrc = 1; -+ else -+ lrc = checkForLilo(lconfig); -+ } - -- if (config->defaultImage == -1) return 0; -- if (config->defaultImage == DEFAULT_SAVED_GRUB2 && -- cfi->defaultIsSaved) -- config->defaultImage = 0; -- entry = findEntryByIndex(config, config->defaultImage); -- if (!entry) return 0; -- if (!suitableImage(entry, bootPrefix, 0, flags)) return 0; -+ if (!access(eliloConfigType.defaultConfig, F_OK)) { -+ econfig = readConfig(eliloConfigType.defaultConfig, -+ &eliloConfigType); -+ if (!econfig) -+ erc = 1; -+ else -+ erc = checkForElilo(econfig); -+ } - -- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); -- if (!line) return 0; -+ if (!access(extlinuxConfigType.defaultConfig, F_OK)) { -+ lconfig = -+ readConfig(extlinuxConfigType.defaultConfig, -+ &extlinuxConfigType); -+ if (!lconfig) -+ extrc = 1; -+ else -+ extrc = checkForExtLinux(lconfig); -+ } - -- rootspec = getRootSpecifier(line->elements[1].item); -- printf("%s%s\n", bootPrefix, line->elements[1].item + -- ((rootspec != NULL) ? strlen(rootspec) : 0)); -+ if (!access(yabootConfigType.defaultConfig, F_OK)) { -+ yconfig = readConfig(yabootConfigType.defaultConfig, -+ &yabootConfigType); -+ if (!yconfig) -+ yrc = 1; -+ else -+ yrc = checkForYaboot(yconfig); -+ } - -- return 0; -+ if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 -+ || erc == 1) -+ return 1; - -- } else if (displayDefaultTitle) { -- struct singleLine * line; -- struct singleEntry * entry; -+ if (lrc == 2) -+ printf("lilo\n"); -+ if (gr2c == 2) -+ printf("grub2\n"); -+ if (grc == 2) -+ printf("grub\n"); -+ if (extrc == 2) -+ printf("extlinux\n"); -+ if (yrc == 2) -+ printf("yaboot\n"); -+ if (erc == 2) -+ printf("elilo\n"); - -- if (config->defaultImage == -1) -- return 0; -- if (config->defaultImage == DEFAULT_SAVED_GRUB2 && -- cfi->defaultIsSaved) -- config->defaultImage = 0; -- entry = findEntryByIndex(config, config->defaultImage); -- if (!entry) - return 0; -+ } -+ -+ if (grubConfig == NULL) { -+ printf("Could not find bootloader configuration file.\n"); -+ exit(1); -+ } -+ -+ config = readConfig(grubConfig, cfi); -+ if (!config) -+ return 1; -+ -+ if (displayDefault) { -+ struct singleLine *line; -+ struct singleEntry *entry; -+ char *rootspec; -+ -+ if (config->defaultImage == -1) -+ return 0; -+ if (config->defaultImage == DEFAULT_SAVED_GRUB2 && -+ cfi->defaultIsSaved) -+ config->defaultImage = 0; -+ entry = findEntryByIndex(config, config->defaultImage); -+ if (!entry) -+ return 0; -+ if (!suitableImage(entry, bootPrefix, 0, flags)) -+ return 0; -+ -+ line = -+ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | -+ LT_KERNEL_16, entry->lines); -+ if (!line) -+ return 0; -+ -+ rootspec = getRootSpecifier(line->elements[1].item); -+ printf("%s%s\n", bootPrefix, line->elements[1].item + -+ ((rootspec != NULL) ? strlen(rootspec) : 0)); - -- if (!configureGrub2) { -- char *title; -- line = getLineByType(LT_TITLE, entry->lines); -- if (!line) - return 0; -- title = extractTitle(config, line); -- if (!title) -+ -+ } else if (displayDefaultTitle) { -+ struct singleLine *line; -+ struct singleEntry *entry; -+ -+ if (config->defaultImage == -1) -+ return 0; -+ if (config->defaultImage == DEFAULT_SAVED_GRUB2 && -+ cfi->defaultIsSaved) -+ config->defaultImage = 0; -+ entry = findEntryByIndex(config, config->defaultImage); -+ if (!entry) -+ return 0; -+ -+ if (!configureGrub2) { -+ char *title; -+ line = getLineByType(LT_TITLE, entry->lines); -+ if (!line) -+ return 0; -+ title = extractTitle(config, line); -+ if (!title) -+ return 0; -+ printf("%s\n", title); -+ free(title); -+ } else { -+ char *title; -+ -+ dbgPrintf -+ ("This is GRUB2, default title is embeded in menuentry\n"); -+ line = getLineByType(LT_MENUENTRY, entry->lines); -+ if (!line) -+ return 0; -+ title = grub2ExtractTitle(line); -+ if (title) -+ printf("%s\n", title); -+ } - return 0; -- printf("%s\n", title); -- free(title); -- } else { -- char * title; - -- dbgPrintf("This is GRUB2, default title is embeded in menuentry\n"); -- line = getLineByType(LT_MENUENTRY, entry->lines); -- if (!line) -+ } else if (displayDefaultIndex) { -+ if (config->defaultImage == -1) -+ return 0; -+ if (config->defaultImage == DEFAULT_SAVED_GRUB2 && -+ cfi->defaultIsSaved) -+ config->defaultImage = 0; -+ printf("%i\n", config->defaultImage); - return 0; -- title = grub2ExtractTitle(line); -- if (title) -- printf("%s\n", title); -+ -+ } else if (kernelInfo) -+ return displayInfo(config, kernelInfo, bootPrefix); -+ -+ if (copyDefault) { -+ template = findTemplate(config, bootPrefix, NULL, 0, flags); -+ if (!template) -+ return 1; - } -- return 0; - -- } else if (displayDefaultIndex) { -- if (config->defaultImage == -1) return 0; -- if (config->defaultImage == DEFAULT_SAVED_GRUB2 && -- cfi->defaultIsSaved) -- config->defaultImage = 0; -- printf("%i\n", config->defaultImage); -- return 0; -- -- } else if (kernelInfo) -- return displayInfo(config, kernelInfo, bootPrefix); -- -- if (copyDefault) { -- template = findTemplate(config, bootPrefix, NULL, 0, flags); -- if (!template) return 1; -- } -- -- markRemovedImage(config, removeKernelPath, bootPrefix); -- markRemovedImage(config, removeMBKernel, bootPrefix); -- setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault, -- bootPrefix, flags, defaultIndex); -- setFallbackImage(config, newKernelPath != NULL); -- if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs, -- removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1; -- if (updateKernelPath && newKernelInitrd) { -- if (newMBKernel) { -- if (addMBInitrd(config, newMBKernel, updateKernelPath, -+ markRemovedImage(config, removeKernelPath, bootPrefix); -+ markRemovedImage(config, removeMBKernel, bootPrefix); -+ setDefaultImage(config, newKernelPath != NULL, defaultKernel, -+ makeDefault, bootPrefix, flags, defaultIndex); -+ setFallbackImage(config, newKernelPath != NULL); -+ if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs, -+ removeArgs, newMBKernelArgs, removeMBKernelArgs)) -+ return 1; -+ if (updateKernelPath && newKernelInitrd) { -+ if (newMBKernel) { -+ if (addMBInitrd(config, newMBKernel, updateKernelPath, - bootPrefix, newKernelInitrd, - newKernelTitle)) -- return 1; -- } else { -- if (updateInitrd(config, updateKernelPath, bootPrefix, -- newKernelInitrd, newKernelTitle)) -- return 1; -- } -- } -- if (addNewKernel(config, template, bootPrefix, newKernelPath, -- newKernelTitle, newKernelArgs, newKernelInitrd, -- (const char **)extraInitrds, extraInitrdCount, -- newMBKernel, newMBKernelArgs)) return 1; -- -- -- if (numEntries(config) == 0) { -- fprintf(stderr, _("grubby: doing this would leave no kernel entries. " -- "Not writing out new config.\n")); -- return 1; -- } -- -- if (!outputFile) -- outputFile = (char *)grubConfig; -- -- return writeConfig(config, outputFile, bootPrefix); -+ return 1; -+ } else { -+ if (updateInitrd(config, updateKernelPath, bootPrefix, -+ newKernelInitrd, newKernelTitle)) -+ return 1; -+ } -+ } -+ if (addNewKernel(config, template, bootPrefix, newKernelPath, -+ newKernelTitle, newKernelArgs, newKernelInitrd, -+ (const char **)extraInitrds, extraInitrdCount, -+ newMBKernel, newMBKernelArgs)) -+ return 1; -+ -+ if (numEntries(config) == 0) { -+ fprintf(stderr, -+ _("grubby: doing this would leave no kernel entries. " -+ "Not writing out new config.\n")); -+ return 1; -+ } -+ -+ if (!outputFile) -+ outputFile = (char *)grubConfig; -+ -+ return writeConfig(config, outputFile, bootPrefix); - } --- -2.4.3 - diff --git a/SOURCES/0003-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch b/SOURCES/0003-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch deleted file mode 100644 index 08a32e5..0000000 --- a/SOURCES/0003-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch +++ /dev/null @@ -1,581 +0,0 @@ -From 8a3357d1257e5e36648c944ff1e461f0f77c88f4 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 6 Aug 2015 10:07:11 -0400 -Subject: [PATCH 3/3] Make SET_VARIABLE get handled individually in - GetNextLine() - -Resolves: rhbz#1152550 - -Signed-off-by: Peter Jones ---- - .gitignore | 2 + - grubby.c | 118 ++++++++++++++++++++++++++------ - test.sh | 8 +++ - test/grub2.16 | 156 +++++++++++++++++++++++++++++++++++++++++++ - test/results/add/g2-1.16 | 170 +++++++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 433 insertions(+), 21 deletions(-) - create mode 100644 test/grub2.16 - create mode 100644 test/results/add/g2-1.16 - -diff --git a/.gitignore b/.gitignore -index e64d3bc..e78a392 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -1,3 +1,5 @@ - grubby - version.h - *.o -+core.* -+vgcore.* -diff --git a/grubby.c b/grubby.c -index 53c11a8..04c5bcb 100644 ---- a/grubby.c -+++ b/grubby.c -@@ -75,6 +75,7 @@ struct lineElement { - }; - - enum lineType_e { -+ LT_UNIDENTIFIED = 0, - LT_WHITESPACE = 1 << 0, - LT_TITLE = 1 << 1, - LT_KERNEL = 1 << 2, -@@ -740,6 +741,33 @@ static char *sdupprintf(const char *format, ...) - return buf; - } - -+static inline int -+kwcmp(struct keywordTypes *kw, const char * label, int case_insensitive) -+{ -+ int kwl = strlen(kw->key); -+ int ll = strlen(label); -+ int rc; -+ int (*snc)(const char *s1, const char *s2, size_t n) = -+ case_insensitive ? strncasecmp : strncmp; -+ int (*sc)(const char *s1, const char *s2) = -+ case_insensitive ? strcasecmp : strcmp; -+ -+ rc = snc(kw->key, label, kwl); -+ if (rc) -+ return rc; -+ -+ for (int i = kwl; i < ll; i++) { -+ if (isspace(label[i])) -+ return 0; -+ if (kw->separatorChar && label[i] == kw->separatorChar) -+ return 0; -+ else if (kw->nextChar && label[i] == kw->nextChar) -+ return 0; -+ return sc(kw->key+kwl, label+kwl); -+ } -+ return 0; -+} -+ - static enum lineType_e preferredLineType(enum lineType_e type, - struct configFileInfo *cfi) - { -@@ -805,13 +833,8 @@ static enum lineType_e getTypeByKeyword(char *keyword, - struct configFileInfo *cfi) - { - for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) { -- if (cfi->caseInsensitive) { -- if (!strcasecmp(keyword, kw->key)) -- return kw->type; -- } else { -- if (!strcmp(keyword, kw->key)) -- return kw->type; -- } -+ if (!kwcmp(kw, keyword, cfi->caseInsensitive)) -+ return kw->type; - } - return LT_UNKNOWN; - } -@@ -906,6 +929,7 @@ static int readFile(int fd, char **bufPtr) - - static void lineInit(struct singleLine *line) - { -+ line->type = LT_UNIDENTIFIED; - line->indent = NULL; - line->elements = NULL; - line->numElements = 0; -@@ -987,7 +1011,7 @@ static int lineWrite(FILE * out, struct singleLine *line, - - if (fprintf(out, "%s", line->elements[i].item) == -1) - return -1; -- if (i < line->numElements - 1) -+ if (i < line->numElements - 1 || line->type == LT_SET_VARIABLE) - if (fprintf(out, "%s", line->elements[i].indent) == -1) - return -1; - } -@@ -1042,6 +1066,8 @@ static int getNextLine(char **bufPtr, struct singleLine *line, - break; - chptr++; - } -+ if (line->type == LT_UNIDENTIFIED) -+ line->type = getTypeByKeyword(start, cfi); - element->item = strndup(start, chptr - start); - start = chptr; - -@@ -1105,7 +1131,7 @@ static int getNextLine(char **bufPtr, struct singleLine *line, - line->type = LT_WHITESPACE; - line->numElements = 0; - } -- } else { -+ } else if (line->type == LT_INITRD) { - struct keywordTypes *kw; - - kw = getKeywordByType(line->type, cfi); -@@ -1167,6 +1193,39 @@ static int getNextLine(char **bufPtr, struct singleLine *line, - } - } - } -+ } else if (line->type == LT_SET_VARIABLE) { -+ /* and if it's a "set blah=" we need to split it -+ * yet a third way to avoid rhbz# XXX FIXME :/ -+ */ -+ char *eq; -+ int l; -+ int numElements = line->numElements; -+ struct lineElement *newElements; -+ eq = strchr(line->elements[1].item, '='); -+ if (!eq) -+ return 0; -+ l = eq - line->elements[1].item; -+ if (eq[1] != 0) -+ numElements++; -+ newElements = calloc(numElements,sizeof (*newElements)); -+ memcpy(&newElements[0], &line->elements[0], -+ sizeof (newElements[0])); -+ newElements[1].item = -+ strndup(line->elements[1].item, l); -+ newElements[1].indent = "="; -+ *(eq++) = '\0'; -+ newElements[2].item = strdup(eq); -+ free(line->elements[1].item); -+ if (line->elements[1].indent) -+ newElements[2].indent = line->elements[1].indent; -+ for (int i = 2; i < line->numElements; i++) { -+ newElements[i+1].item = line->elements[i].item; -+ newElements[i+1].indent = -+ line->elements[i].indent; -+ } -+ free(line->elements); -+ line->elements = newElements; -+ line->numElements = numElements; - } - } - -@@ -1272,8 +1331,8 @@ static struct grubConfig *readConfig(const char *inName, - getKeywordByType(LT_DEFAULT, cfi); - if (kwType && line->numElements == 3 - && !strcmp(line->elements[1].item, kwType->key) -- && !is_special_grub2_variable(line->elements[2]. -- item)) { -+ && !is_special_grub2_variable( -+ line->elements[2].item)) { - dbgPrintf("Line sets default config\n"); - cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; - defaultLine = line; -@@ -1529,16 +1588,33 @@ static struct grubConfig *readConfig(const char *inName, - } - } - } else if (cfi->defaultIsVariable) { -- char *value = defaultLine->elements[2].item; -- while (*value && (*value == '"' || *value == '\'' || -- *value == ' ' || *value == '\t')) -- value++; -- cfg->defaultImage = strtol(value, &end, 10); -- while (*end && (*end == '"' || *end == '\'' || -- *end == ' ' || *end == '\t')) -- end++; -- if (*end) -- cfg->defaultImage = -1; -+ if (defaultLine->numElements == 2) { -+ char *value = defaultLine->elements[1].item + 8; -+ while (*value && (*value == '"' || -+ *value == '\'' || -+ *value == ' ' || -+ *value == '\t')) -+ value++; -+ cfg->defaultImage = strtol(value, &end, 10); -+ while (*end && (*end == '"' || *end == '\'' || -+ *end == ' ' || *end == '\t')) -+ end++; -+ if (*end) -+ cfg->defaultImage = -1; -+ } else if (defaultLine->numElements == 3) { -+ char *value = defaultLine->elements[2].item; -+ while (*value && (*value == '"' || -+ *value == '\'' || -+ *value == ' ' || -+ *value == '\t')) -+ value++; -+ cfg->defaultImage = strtol(value, &end, 10); -+ while (*end && (*end == '"' || *end == '\'' || -+ *end == ' ' || *end == '\t')) -+ end++; -+ if (*end) -+ cfg->defaultImage = -1; -+ } - } else if (cfi->defaultSupportSaved && - !strncmp(defaultLine->elements[1].item, "saved", - 5)) { -diff --git a/test.sh b/test.sh -index c2a66e2..9e9be23 100755 ---- a/test.sh -+++ b/test.sh -@@ -542,6 +542,14 @@ if [ "$testgrub2" == "y" ]; then - ;; - esac - -+ # a grub2 add with a "set" of the form: set foo="bar=1,2". bz#1152550 -+ # has this being emitted as: set foo="bar=1,2"=1,2" -+ # which is wrong. -+ grub2Test grub2.16 add/g2-1.16 \ -+ --add-kernel=/boot/vmlinuz-foo \ -+ --copy-default --title 'Red Hat Enterprise Linux Server' \ -+ --args=root=/dev/mapper/foo-- -+ - testing="GRUB2 add initrd" - grub2Test grub2.2 add/g2-1.4 --update-kernel=/boot/new-kernel.img \ - --initrd=/boot/new-initrd --boot-filesystem=/boot/ -diff --git a/test/grub2.16 b/test/grub2.16 -new file mode 100644 -index 0000000..136880a ---- /dev/null -+++ b/test/grub2.16 -@@ -0,0 +1,156 @@ -+# -+# DO NOT EDIT THIS FILE -+# -+# It is automatically generated by grub2-mkconfig using templates -+# from /etc/grub.d and settings from /etc/default/grub -+# -+ -+### BEGIN /etc/grub.d/00_header ### -+set pager=1 -+ -+if [ -s $prefix/grubenv ]; then -+ load_env -+fi -+if [ "${next_entry}" ] ; then -+ set default="${next_entry}" -+ set next_entry= -+ save_env next_entry -+ set boot_once=true -+else -+ set default="${saved_entry}" -+fi -+ -+if [ x"${feature_menuentry_id}" = xy ]; then -+ menuentry_id_option="--id" -+else -+ menuentry_id_option="" -+fi -+ -+export menuentry_id_option -+ -+if [ "${prev_saved_entry}" ]; then -+ set saved_entry="${prev_saved_entry}" -+ save_env saved_entry -+ set prev_saved_entry= -+ save_env prev_saved_entry -+ set boot_once=true -+fi -+ -+function savedefault { -+ if [ -z "${boot_once}" ]; then -+ saved_entry="${chosen}" -+ save_env saved_entry -+ fi -+} -+ -+function load_video { -+ if [ x$feature_all_video_module = xy ]; then -+ insmod all_video -+ else -+ insmod efi_gop -+ insmod efi_uga -+ insmod ieee1275_fb -+ insmod vbe -+ insmod vga -+ insmod video_bochs -+ insmod video_cirrus -+ fi -+} -+ -+serial --speed=115200 -+terminal_input serial console -+terminal_output serial console -+if [ x$feature_timeout_style = xy ] ; then -+ set timeout_style=menu -+ set timeout=5 -+# Fallback normal timeout code in case the timeout_style feature is -+# unavailable. -+else -+ set timeout=5 -+fi -+### END /etc/grub.d/00_header ### -+ -+### BEGIN /etc/grub.d/00_tuned ### -+set tuned_params="isolcpus=1,3" -+### END /etc/grub.d/00_tuned ### -+ -+### BEGIN /etc/grub.d/01_users ### -+if [ -f ${prefix}/user.cfg ]; then -+ source ${prefix}/user.cfg -+ if [ -n ${GRUB2_PASSWORD} ]; then -+ set superusers="root" -+ export superusers -+ password_pbkdf2 root ${GRUB2_PASSWORD} -+ fi -+fi -+### END /etc/grub.d/01_users ### -+ -+### BEGIN /etc/grub.d/10_linux ### -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 -+} -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-3.10.0-296.el7.x86_64.img -+} -+menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img -+} -+if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; -+### END /etc/grub.d/10_linux ### -+ -+### BEGIN /etc/grub.d/20_linux_xen ### -+### END /etc/grub.d/20_linux_xen ### -+ -+### BEGIN /etc/grub.d/20_ppc_terminfo ### -+### END /etc/grub.d/20_ppc_terminfo ### -+ -+### BEGIN /etc/grub.d/30_os-prober ### -+### END /etc/grub.d/30_os-prober ### -+ -+### BEGIN /etc/grub.d/40_custom ### -+# This file provides an easy way to add custom menu entries. Simply type the -+# menu entries you want to add after this comment. Be careful not to change -+# the 'exec tail' line above. -+### END /etc/grub.d/40_custom ### -+ -+### BEGIN /etc/grub.d/41_custom ### -+if [ -f ${config_directory}/custom.cfg ]; then -+ source ${config_directory}/custom.cfg -+elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then -+ source $prefix/custom.cfg; -+fi -+### END /etc/grub.d/41_custom ### -diff --git a/test/results/add/g2-1.16 b/test/results/add/g2-1.16 -new file mode 100644 -index 0000000..fc98757 ---- /dev/null -+++ b/test/results/add/g2-1.16 -@@ -0,0 +1,170 @@ -+# -+# DO NOT EDIT THIS FILE -+# -+# It is automatically generated by grub2-mkconfig using templates -+# from /etc/grub.d and settings from /etc/default/grub -+# -+ -+### BEGIN /etc/grub.d/00_header ### -+set pager=1 -+ -+if [ -s $prefix/grubenv ]; then -+ load_env -+fi -+if [ "${next_entry}" ] ; then -+ set default="${next_entry}" -+ set next_entry= -+ save_env next_entry -+ set boot_once=true -+else -+ set default="${saved_entry}" -+fi -+ -+if [ x"${feature_menuentry_id}" = xy ]; then -+ menuentry_id_option="--id" -+else -+ menuentry_id_option="" -+fi -+ -+export menuentry_id_option -+ -+if [ "${prev_saved_entry}" ]; then -+ set saved_entry="${prev_saved_entry}" -+ save_env saved_entry -+ set prev_saved_entry= -+ save_env prev_saved_entry -+ set boot_once=true -+fi -+ -+function savedefault { -+ if [ -z "${boot_once}" ]; then -+ saved_entry="${chosen}" -+ save_env saved_entry -+ fi -+} -+ -+function load_video { -+ if [ x$feature_all_video_module = xy ]; then -+ insmod all_video -+ else -+ insmod efi_gop -+ insmod efi_uga -+ insmod ieee1275_fb -+ insmod vbe -+ insmod vga -+ insmod video_bochs -+ insmod video_cirrus -+ fi -+} -+ -+serial --speed=115200 -+terminal_input serial console -+terminal_output serial console -+if [ x$feature_timeout_style = xy ] ; then -+ set timeout_style=menu -+ set timeout=5 -+# Fallback normal timeout code in case the timeout_style feature is -+# unavailable. -+else -+ set timeout=5 -+fi -+### END /etc/grub.d/00_header ### -+ -+### BEGIN /etc/grub.d/00_tuned ### -+set tuned_params="isolcpus=1,3" -+### END /etc/grub.d/00_tuned ### -+ -+### BEGIN /etc/grub.d/01_users ### -+if [ -f ${prefix}/user.cfg ]; then -+ source ${prefix}/user.cfg -+ if [ -n ${GRUB2_PASSWORD} ]; then -+ set superusers="root" -+ export superusers -+ password_pbkdf2 root ${GRUB2_PASSWORD} -+ fi -+fi -+### END /etc/grub.d/01_users ### -+ -+### BEGIN /etc/grub.d/10_linux ### -+menuentry 'Red Hat Enterprise Linux Server' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-foo root=/dev/mapper/foo-- ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 -+} -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 -+} -+menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ set gfxpayload=keep -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-3.10.0-296.el7.x86_64.img -+} -+menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { -+ load_video -+ insmod gzio -+ insmod part_msdos -+ insmod xfs -+ set root='hd0,msdos1' -+ if [ x$feature_platform_search_hint = xy ]; then -+ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 -+ else -+ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 -+ fi -+ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params -+ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img -+} -+if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; -+### END /etc/grub.d/10_linux ### -+ -+### BEGIN /etc/grub.d/20_linux_xen ### -+### END /etc/grub.d/20_linux_xen ### -+ -+### BEGIN /etc/grub.d/20_ppc_terminfo ### -+### END /etc/grub.d/20_ppc_terminfo ### -+ -+### BEGIN /etc/grub.d/30_os-prober ### -+### END /etc/grub.d/30_os-prober ### -+ -+### BEGIN /etc/grub.d/40_custom ### -+# This file provides an easy way to add custom menu entries. Simply type the -+# menu entries you want to add after this comment. Be careful not to change -+# the 'exec tail' line above. -+### END /etc/grub.d/40_custom ### -+ -+### BEGIN /etc/grub.d/41_custom ### -+if [ -f ${config_directory}/custom.cfg ]; then -+ source ${config_directory}/custom.cfg -+elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then -+ source $prefix/custom.cfg; -+fi -+### END /etc/grub.d/41_custom ### --- -2.4.3 - diff --git a/SOURCES/0042-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch b/SOURCES/0042-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch new file mode 100644 index 0000000..f4971af --- /dev/null +++ b/SOURCES/0042-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch @@ -0,0 +1,42 @@ +From 8f0ef3e08aaef134ec4acfe87a6628b3fda2243c Mon Sep 17 00:00:00 2001 +From: Don Zickus +Date: Wed, 22 Jul 2015 13:58:53 -0400 +Subject: [PATCH] ppc64le sync grub.cfg changes to disk (#1212114) + +After installing a new kernel, if a panic is induced, not all the kernel +pieces are on the disk (most importantly the grub.cfg changes). This can +lead to a hung system on a reboot because the older kernel can not be found. + +Address this by forcing all the changes (mainly the fs meta data) to disk +before finishing the kernel package installation. + +Tested by 'yum install kernel-...; echo c > /proc/sysrq-trigger'. + +Before, the machine would panic and on reboot be stuck without a grub.cfg +to read. After, works as expected. + +Related: rhbz#1212114 +--- + new-kernel-pkg | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/new-kernel-pkg b/new-kernel-pkg +index 1f6ab39..90652da 100755 +--- a/new-kernel-pkg ++++ b/new-kernel-pkg +@@ -927,4 +927,12 @@ fi + # if we mounted the U-Boot directory, unmount it. + [ -n "$mounted" ] && umount $ubootDir + ++# make sure changes make it to the disk. ++# if /boot is a mountpoint, force the meta data on disk ++# to by-pass writeback delay. ++# PPC64LE-only to deal with Petitboot issues ++if [ "$ARCH" = "ppc64le" ]; then ++ sync && mountpoint -q /boot &&fsfreeze -f /boot && fsfreeze -u /boot ++fi ++ + exit 0 +-- +1.8.3.1 + diff --git a/SOURCES/0043-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch b/SOURCES/0043-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch new file mode 100644 index 0000000..8ccf23b --- /dev/null +++ b/SOURCES/0043-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch @@ -0,0 +1,38 @@ +From 956c9b804607d1a43183514e8a18d671ab14d2fa Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 6 Aug 2015 10:06:13 -0400 +Subject: [PATCH 1/3] Make it possible to run "test.sh --verbose" from the make + command line. + +Signed-off-by: Peter Jones +--- + Makefile | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 94cef27..e021f35 100644 +--- a/Makefile ++++ b/Makefile +@@ -26,6 +26,10 @@ CC = gcc + RPM_OPT_FLAGS ?= -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector + CFLAGS += $(RPM_OPT_FLAGS) -std=gnu99 -Wall -Werror -Wno-error=unused-function -Wno-unused-function -ggdb + LDFLAGS := ++VERBOSE_TEST := ++ifneq ($(VERBOSE_TEST),) ++ VERBOSE_TEST="--verbose" ++endif + + grubby_LIBS = -lblkid -lpopt + +@@ -39,7 +43,7 @@ debug : clean + + test: all + @export TOPDIR=$(TOPDIR) +- @./test.sh ++ @./test.sh $(VERBOSE_TEST) + + install: all + mkdir -p $(DESTDIR)$(PREFIX)/sbin +-- +2.4.3 + diff --git a/SOURCES/0044-Don-t-leak-from-one-extractTitle-call.patch b/SOURCES/0044-Don-t-leak-from-one-extractTitle-call.patch new file mode 100644 index 0000000..6489935 --- /dev/null +++ b/SOURCES/0044-Don-t-leak-from-one-extractTitle-call.patch @@ -0,0 +1,85 @@ +From 7713f8e23e326dcf1258a715e2554a4bf53dec59 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 2 Jul 2015 16:26:59 -0400 +Subject: [PATCH] Don't leak from one extractTitle() call. + +Found by coverity. + +Signed-off-by: Peter Jones +--- + grubby.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/grubby.c b/grubby.c +index 0bb4869..70477ba 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -1510,13 +1510,14 @@ static struct grubConfig * readConfig(const char * inName, + return cfg; + } + +-static void writeDefault(FILE * out, char * indent, ++static void writeDefault(FILE * out, char * indent, + char * separator, struct grubConfig * cfg) { + struct singleEntry * entry; + struct singleLine * line; + int i; + +- if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) return; ++ if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) ++ return; + + if (cfg->defaultImage == DEFAULT_SAVED) + fprintf(out, "%sdefault%ssaved\n", indent, separator); +@@ -1540,34 +1541,40 @@ static void writeDefault(FILE * out, char * indent, + fprintf(out, "%sset default=\"%d\"\n", indent, + cfg->defaultImage); + } else { +- fprintf(out, "%sdefault%s%d\n", indent, separator, ++ fprintf(out, "%sdefault%s%d\n", indent, separator, + cfg->defaultImage); + } + } else { + int image = cfg->defaultImage; + + entry = cfg->entries; +- while (entry && entry->skip) entry = entry->next; ++ while (entry && entry->skip) ++ entry = entry->next; + + i = 0; + while (entry && i < image) { + entry = entry->next; + +- while (entry && entry->skip) entry = entry->next; ++ while (entry && entry->skip) ++ entry = entry->next; + i++; + } + +- if (!entry) return; ++ if (!entry) ++ return; + + line = getLineByType(LT_TITLE, entry->lines); + + if (line && line->numElements >= 2) +- fprintf(out, "%sdefault%s%s\n", indent, separator, ++ fprintf(out, "%sdefault%s%s\n", indent, separator, + line->elements[1].item); +- else if (line && (line->numElements == 1) && ++ else if (line && (line->numElements == 1) && + cfg->cfi->titleBracketed) { +- fprintf(out, "%sdefault%s%s\n", indent, separator, +- extractTitle(cfg, line)); ++ char *title = extractTitle(cfg, line); ++ if (title) { ++ fprintf(out, "%sdefault%s%s\n", indent, separator, title); ++ free(title); ++ } + } + } + } +-- +2.4.3 + diff --git a/SOURCES/0045-Better-formatting.patch b/SOURCES/0045-Better-formatting.patch new file mode 100644 index 0000000..fafdd95 --- /dev/null +++ b/SOURCES/0045-Better-formatting.patch @@ -0,0 +1,9034 @@ +From aaea1dbe7731a481a1f62b312a5dd5ac77c10926 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 10 Sep 2015 18:27:31 -0400 +Subject: [PATCH] Reformat to make this easier to work on. + +Signed-off-by: Peter Jones +--- + grubby.c | 8385 +++++++++++++++++++++++++++++++++----------------------------- + 1 file changed, 4406 insertions(+), 3979 deletions(-) + +diff --git a/grubby.c b/grubby.c +index f1af54d..8295a53 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -48,7 +48,7 @@ + #define dbgPrintf(format, args...) + #endif + +-int debug = 0; /* Currently just for template debugging */ ++int debug = 0; /* Currently just for template debugging */ + + #define _(A) (A) + +@@ -70,50 +70,50 @@ char *saved_command_line = NULL; + + /* comments get lumped in with indention */ + struct lineElement { +- char * item; +- char * indent; ++ char *item; ++ char *indent; + }; + +-enum lineType_e { +- LT_WHITESPACE = 1 << 0, +- LT_TITLE = 1 << 1, +- LT_KERNEL = 1 << 2, +- LT_INITRD = 1 << 3, +- LT_HYPER = 1 << 4, +- LT_DEFAULT = 1 << 5, +- LT_MBMODULE = 1 << 6, +- LT_ROOT = 1 << 7, +- LT_FALLBACK = 1 << 8, +- LT_KERNELARGS = 1 << 9, +- LT_BOOT = 1 << 10, +- LT_BOOTROOT = 1 << 11, +- LT_LBA = 1 << 12, +- LT_OTHER = 1 << 13, +- LT_GENERIC = 1 << 14, +- LT_ECHO = 1 << 16, +- LT_MENUENTRY = 1 << 17, +- LT_ENTRY_END = 1 << 18, +- LT_SET_VARIABLE = 1 << 19, +- LT_KERNEL_EFI = 1 << 20, +- LT_INITRD_EFI = 1 << 21, +- LT_KERNEL_16 = 1 << 22, +- LT_INITRD_16 = 1 << 23, +- LT_UNKNOWN = 1 << 24, ++enum lineType_e { ++ LT_WHITESPACE = 1 << 0, ++ LT_TITLE = 1 << 1, ++ LT_KERNEL = 1 << 2, ++ LT_INITRD = 1 << 3, ++ LT_HYPER = 1 << 4, ++ LT_DEFAULT = 1 << 5, ++ LT_MBMODULE = 1 << 6, ++ LT_ROOT = 1 << 7, ++ LT_FALLBACK = 1 << 8, ++ LT_KERNELARGS = 1 << 9, ++ LT_BOOT = 1 << 10, ++ LT_BOOTROOT = 1 << 11, ++ LT_LBA = 1 << 12, ++ LT_OTHER = 1 << 13, ++ LT_GENERIC = 1 << 14, ++ LT_ECHO = 1 << 16, ++ LT_MENUENTRY = 1 << 17, ++ LT_ENTRY_END = 1 << 18, ++ LT_SET_VARIABLE = 1 << 19, ++ LT_KERNEL_EFI = 1 << 20, ++ LT_INITRD_EFI = 1 << 21, ++ LT_KERNEL_16 = 1 << 22, ++ LT_INITRD_16 = 1 << 23, ++ LT_UNKNOWN = 1 << 24, + }; + + struct singleLine { +- char * indent; +- int numElements; +- struct lineElement * elements; +- struct singleLine * next; +- enum lineType_e type; ++ char *indent; ++ int numElements; ++ struct lineElement *elements; ++ struct singleLine *next; ++ enum lineType_e type; + }; + + struct singleEntry { +- struct singleLine * lines; +- int skip; +- int multiboot; +- struct singleEntry * next; ++ struct singleLine *lines; ++ int skip; ++ int multiboot; ++ struct singleEntry *next; + }; + + #define GRUBBY_BADIMAGE_OKAY (1 << 0) +@@ -133,1718 +133,1837 @@ struct singleEntry { + #define DEFAULT_SAVED_GRUB2 -3 + + struct keywordTypes { +- char * key; +- enum lineType_e type; +- char nextChar; +- char separatorChar; ++ char *key; ++ enum lineType_e type; ++ char nextChar; ++ char separatorChar; + }; + + struct configFileInfo; + +-typedef const char *(*findConfigFunc)(struct configFileInfo *); +-typedef const int (*writeLineFunc)(struct configFileInfo *, +- struct singleLine *line); +-typedef char *(*getEnvFunc)(struct configFileInfo *, char *name); +-typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value); ++typedef const char *(*findConfigFunc) (struct configFileInfo *); ++typedef const int (*writeLineFunc) (struct configFileInfo *, ++ struct singleLine * line); ++typedef char *(*getEnvFunc) (struct configFileInfo *, char *name); ++typedef int (*setEnvFunc) (struct configFileInfo *, char *name, char *value); + + struct configFileInfo { +- char * defaultConfig; +- findConfigFunc findConfig; +- writeLineFunc writeLine; +- getEnvFunc getEnv; +- setEnvFunc setEnv; +- struct keywordTypes * keywords; +- int caseInsensitive; +- int defaultIsIndex; +- int defaultIsVariable; +- int defaultSupportSaved; +- int defaultIsSaved; +- int defaultIsUnquoted; +- enum lineType_e entryStart; +- enum lineType_e entryEnd; +- int needsBootPrefix; +- int argsInQuotes; +- int maxTitleLength; +- int titleBracketed; +- int titlePosition; +- int mbHyperFirst; +- int mbInitRdIsModule; +- int mbConcatArgs; +- int mbAllowExtraInitRds; +- char *envFile; ++ char *defaultConfig; ++ findConfigFunc findConfig; ++ writeLineFunc writeLine; ++ getEnvFunc getEnv; ++ setEnvFunc setEnv; ++ struct keywordTypes *keywords; ++ int caseInsensitive; ++ int defaultIsIndex; ++ int defaultIsVariable; ++ int defaultSupportSaved; ++ int defaultIsSaved; ++ int defaultIsUnquoted; ++ enum lineType_e entryStart; ++ enum lineType_e entryEnd; ++ int needsBootPrefix; ++ int argsInQuotes; ++ int maxTitleLength; ++ int titleBracketed; ++ int titlePosition; ++ int mbHyperFirst; ++ int mbInitRdIsModule; ++ int mbConcatArgs; ++ int mbAllowExtraInitRds; ++ char *envFile; + }; + + struct keywordTypes grubKeywords[] = { +- { "title", LT_TITLE, ' ' }, +- { "root", LT_BOOTROOT, ' ' }, +- { "default", LT_DEFAULT, ' ' }, +- { "fallback", LT_FALLBACK, ' ' }, +- { "kernel", LT_KERNEL, ' ' }, +- { "initrd", LT_INITRD, ' ', ' ' }, +- { "module", LT_MBMODULE, ' ' }, +- { "kernel", LT_HYPER, ' ' }, +- { NULL, 0, 0 }, ++ {"title", LT_TITLE, ' '}, ++ {"root", LT_BOOTROOT, ' '}, ++ {"default", LT_DEFAULT, ' '}, ++ {"fallback", LT_FALLBACK, ' '}, ++ {"kernel", LT_KERNEL, ' '}, ++ {"initrd", LT_INITRD, ' ', ' '}, ++ {"module", LT_MBMODULE, ' '}, ++ {"kernel", LT_HYPER, ' '}, ++ {NULL, 0, 0}, + }; + +-const char *grubFindConfig(struct configFileInfo *cfi) { +- static const char *configFiles[] = { +- "/boot/grub/menu.lst", +- "/etc/grub.conf", +- NULL +- }; +- static int i = -1; +- +- if (i == -1) { +- for (i = 0; configFiles[i] != NULL; i++) { +- dbgPrintf("Checking \"%s\": ", configFiles[i]); +- if (!access(configFiles[i], R_OK)) { +- dbgPrintf("found\n"); +- return configFiles[i]; +- } +- dbgPrintf("not found\n"); ++const char *grubFindConfig(struct configFileInfo *cfi) ++{ ++ static const char *configFiles[] = { ++ "/boot/grub/menu.lst", ++ "/etc/grub.conf", ++ NULL ++ }; ++ static int i = -1; ++ ++ if (i == -1) { ++ for (i = 0; configFiles[i] != NULL; i++) { ++ dbgPrintf("Checking \"%s\": ", configFiles[i]); ++ if (!access(configFiles[i], R_OK)) { ++ dbgPrintf("found\n"); ++ return configFiles[i]; ++ } ++ dbgPrintf("not found\n"); ++ } + } +- } +- return configFiles[i]; ++ return configFiles[i]; + } + + struct configFileInfo grubConfigType = { +- .findConfig = grubFindConfig, +- .keywords = grubKeywords, +- .defaultIsIndex = 1, +- .defaultSupportSaved = 1, +- .entryStart = LT_TITLE, +- .needsBootPrefix = 1, +- .mbHyperFirst = 1, +- .mbInitRdIsModule = 1, +- .mbAllowExtraInitRds = 1, +- .titlePosition = 1, ++ .findConfig = grubFindConfig, ++ .keywords = grubKeywords, ++ .defaultIsIndex = 1, ++ .defaultSupportSaved = 1, ++ .entryStart = LT_TITLE, ++ .needsBootPrefix = 1, ++ .mbHyperFirst = 1, ++ .mbInitRdIsModule = 1, ++ .mbAllowExtraInitRds = 1, ++ .titlePosition = 1, + }; + + struct keywordTypes grub2Keywords[] = { +- { "menuentry", LT_MENUENTRY, ' ' }, +- { "}", LT_ENTRY_END, ' ' }, +- { "echo", LT_ECHO, ' ' }, +- { "set", LT_SET_VARIABLE,' ', '=' }, +- { "root", LT_BOOTROOT, ' ' }, +- { "default", LT_DEFAULT, ' ' }, +- { "fallback", LT_FALLBACK, ' ' }, +- { "linux", LT_KERNEL, ' ' }, +- { "linuxefi", LT_KERNEL_EFI, ' ' }, +- { "linux16", LT_KERNEL_16, ' ' }, +- { "initrd", LT_INITRD, ' ', ' ' }, +- { "initrdefi", LT_INITRD_EFI, ' ', ' ' }, +- { "initrd16", LT_INITRD_16, ' ', ' ' }, +- { "module", LT_MBMODULE, ' ' }, +- { "kernel", LT_HYPER, ' ' }, +- { NULL, 0, 0 }, ++ {"menuentry", LT_MENUENTRY, ' '}, ++ {"}", LT_ENTRY_END, ' '}, ++ {"echo", LT_ECHO, ' '}, ++ {"set", LT_SET_VARIABLE, ' ', '='}, ++ {"root", LT_BOOTROOT, ' '}, ++ {"default", LT_DEFAULT, ' '}, ++ {"fallback", LT_FALLBACK, ' '}, ++ {"linux", LT_KERNEL, ' '}, ++ {"linuxefi", LT_KERNEL_EFI, ' '}, ++ {"linux16", LT_KERNEL_16, ' '}, ++ {"initrd", LT_INITRD, ' ', ' '}, ++ {"initrdefi", LT_INITRD_EFI, ' ', ' '}, ++ {"initrd16", LT_INITRD_16, ' ', ' '}, ++ {"module", LT_MBMODULE, ' '}, ++ {"kernel", LT_HYPER, ' '}, ++ {NULL, 0, 0}, + }; + +-const char *grub2FindConfig(struct configFileInfo *cfi) { +- static const char *configFiles[] = { +- "/etc/grub2-efi.cfg", +- "/etc/grub2.cfg", +- NULL +- }; +- static int i = -1; +- static const char *grub_cfg = "/boot/grub/grub.cfg"; +- int rc = -1; +- +- if (i == -1) { +- for (i = 0; configFiles[i] != NULL; i++) { +- dbgPrintf("Checking \"%s\": ", configFiles[i]); +- if ((rc = access(configFiles[i], R_OK))) { +- if (errno == EACCES) { +- printf("Unable to access bootloader configuration file " +- "\"%s\": %m\n", configFiles[i]); +- exit(1); ++const char *grub2FindConfig(struct configFileInfo *cfi) ++{ ++ static const char *configFiles[] = { ++ "/etc/grub2-efi.cfg", ++ "/etc/grub2.cfg", ++ NULL ++ }; ++ static int i = -1; ++ static const char *grub_cfg = "/boot/grub/grub.cfg"; ++ int rc = -1; ++ ++ if (i == -1) { ++ for (i = 0; configFiles[i] != NULL; i++) { ++ dbgPrintf("Checking \"%s\": ", configFiles[i]); ++ if ((rc = access(configFiles[i], R_OK))) { ++ if (errno == EACCES) { ++ printf ++ ("Unable to access bootloader configuration file " ++ "\"%s\": %m\n", configFiles[i]); ++ exit(1); ++ } ++ continue; ++ } else { ++ dbgPrintf("found\n"); ++ return configFiles[i]; ++ } + } +- continue; +- } else { +- dbgPrintf("found\n"); +- return configFiles[i]; +- } + } +- } + +- /* Ubuntu renames grub2 to grub, so check for the grub.d directory +- * that isn't in grub1, and if it exists, return the config file path +- * that they use. */ +- if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) { +- dbgPrintf("found\n"); +- return grub_cfg; +- } ++ /* Ubuntu renames grub2 to grub, so check for the grub.d directory ++ * that isn't in grub1, and if it exists, return the config file path ++ * that they use. */ ++ if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) { ++ dbgPrintf("found\n"); ++ return grub_cfg; ++ } + +- dbgPrintf("not found\n"); +- return configFiles[i]; ++ dbgPrintf("not found\n"); ++ return configFiles[i]; + } + + /* kind of hacky. It'll give the first 1024 bytes, ish. */ + static char *grub2GetEnv(struct configFileInfo *info, char *name) + { +- static char buf[1025]; +- char *s = NULL; +- char *ret = NULL; +- char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; +- int rc = asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name); +- +- if (rc < 0) +- return NULL; +- +- FILE *f = popen(s, "r"); +- if (!f) +- goto out; +- +- memset(buf, '\0', sizeof (buf)); +- ret = fgets(buf, 1024, f); +- pclose(f); +- +- if (ret) { +- ret += strlen(name) + 1; +- ret[strlen(ret) - 1] = '\0'; +- } +- dbgPrintf("grub2GetEnv(%s): %s\n", name, ret); ++ static char buf[1025]; ++ char *s = NULL; ++ char *ret = NULL; ++ char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; ++ int rc = ++ asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name); ++ ++ if (rc < 0) ++ return NULL; ++ ++ FILE *f = popen(s, "r"); ++ if (!f) ++ goto out; ++ ++ memset(buf, '\0', sizeof(buf)); ++ ret = fgets(buf, 1024, f); ++ pclose(f); ++ ++ if (ret) { ++ ret += strlen(name) + 1; ++ ret[strlen(ret) - 1] = '\0'; ++ } ++ dbgPrintf("grub2GetEnv(%s): %s\n", name, ret); + out: +- free(s); +- return ret; ++ free(s); ++ return ret; + } + + static int sPopCount(const char *s, const char *c) + { +- int ret = 0; +- if (!s) +- return -1; +- for (int i = 0; s[i] != '\0'; i++) +- for (int j = 0; c[j] != '\0'; j++) +- if (s[i] == c[j]) +- ret++; +- return ret; ++ int ret = 0; ++ if (!s) ++ return -1; ++ for (int i = 0; s[i] != '\0'; i++) ++ for (int j = 0; c[j] != '\0'; j++) ++ if (s[i] == c[j]) ++ ret++; ++ return ret; + } + + static char *shellEscape(const char *s) + { +- int l = strlen(s) + sPopCount(s, "'") * 2; +- +- char *ret = calloc(l+1, sizeof (*ret)); +- if (!ret) +- return NULL; +- for (int i = 0, j = 0; s[i] != '\0'; i++, j++) { +- if (s[i] == '\'') +- ret[j++] = '\\'; +- ret[j] = s[i]; +- } +- return ret; ++ int l = strlen(s) + sPopCount(s, "'") * 2; ++ ++ char *ret = calloc(l + 1, sizeof(*ret)); ++ if (!ret) ++ return NULL; ++ for (int i = 0, j = 0; s[i] != '\0'; i++, j++) { ++ if (s[i] == '\'') ++ ret[j++] = '\\'; ++ ret[j] = s[i]; ++ } ++ return ret; + } + + static void unquote(char *s) + { +- int l = strlen(s); ++ int l = strlen(s); + +- if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) { +- memmove(s, s+1, l-2); +- s[l-2] = '\0'; +- } ++ if ((s[l - 1] == '\'' && s[0] == '\'') ++ || (s[l - 1] == '"' && s[0] == '"')) { ++ memmove(s, s + 1, l - 2); ++ s[l - 2] = '\0'; ++ } + } + + static int grub2SetEnv(struct configFileInfo *info, char *name, char *value) + { +- char *s = NULL; +- int rc = 0; +- char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; +- +- unquote(value); +- value = shellEscape(value); +- if (!value) +- return -1; +- +- rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value); +- free(value); +- if (rc <0) +- return -1; +- +- dbgPrintf("grub2SetEnv(%s): %s\n", name, s); +- rc = system(s); +- free(s); +- return rc; ++ char *s = NULL; ++ int rc = 0; ++ char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; ++ ++ unquote(value); ++ value = shellEscape(value); ++ if (!value) ++ return -1; ++ ++ rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value); ++ free(value); ++ if (rc < 0) ++ return -1; ++ ++ dbgPrintf("grub2SetEnv(%s): %s\n", name, s); ++ rc = system(s); ++ free(s); ++ return rc; + } + + /* this is a gigantic hack to avoid clobbering grub2 variables... */ + static int is_special_grub2_variable(const char *name) + { +- if (!strcmp(name,"\"${next_entry}\"")) +- return 1; +- if (!strcmp(name,"\"${prev_saved_entry}\"")) +- return 1; +- return 0; ++ if (!strcmp(name, "\"${next_entry}\"")) ++ return 1; ++ if (!strcmp(name, "\"${prev_saved_entry}\"")) ++ return 1; ++ return 0; + } + +-int sizeOfSingleLine(struct singleLine * line) { +- int count = 0; ++int sizeOfSingleLine(struct singleLine *line) ++{ ++ int count = 0; + +- for (int i = 0; i < line->numElements; i++) { +- int indentSize = 0; ++ for (int i = 0; i < line->numElements; i++) { ++ int indentSize = 0; + +- count = count + strlen(line->elements[i].item); ++ count = count + strlen(line->elements[i].item); + +- indentSize = strlen(line->elements[i].indent); +- if (indentSize > 0) +- count = count + indentSize; +- else +- /* be extra safe and add room for whitespaces */ +- count = count + 1; +- } ++ indentSize = strlen(line->elements[i].indent); ++ if (indentSize > 0) ++ count = count + indentSize; ++ else ++ /* be extra safe and add room for whitespaces */ ++ count = count + 1; ++ } + +- /* room for trailing terminator */ +- count = count + 1; ++ /* room for trailing terminator */ ++ count = count + 1; + +- return count; ++ return count; + } + + static int isquote(char q) + { +- if (q == '\'' || q == '\"') +- return 1; +- return 0; ++ if (q == '\'' || q == '\"') ++ return 1; ++ return 0; + } + +-static int iskernel(enum lineType_e type) { +- return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16); ++static int iskernel(enum lineType_e type) ++{ ++ return (type == LT_KERNEL || type == LT_KERNEL_EFI ++ || type == LT_KERNEL_16); + } + +-static int isinitrd(enum lineType_e type) { +- return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16); ++static int isinitrd(enum lineType_e type) ++{ ++ return (type == LT_INITRD || type == LT_INITRD_EFI ++ || type == LT_INITRD_16); + } + +-char *grub2ExtractTitle(struct singleLine * line) { +- char * current; +- char * current_indent; +- int current_len; +- int current_indent_len; +- int i; ++char *grub2ExtractTitle(struct singleLine *line) ++{ ++ char *current; ++ char *current_indent; ++ int current_len; ++ int current_indent_len; ++ int i; + +- /* bail out if line does not start with menuentry */ +- if (strcmp(line->elements[0].item, "menuentry")) +- return NULL; ++ /* bail out if line does not start with menuentry */ ++ if (strcmp(line->elements[0].item, "menuentry")) ++ return NULL; + +- i = 1; +- current = line->elements[i].item; +- current_len = strlen(current); +- +- /* if second word is quoted, strip the quotes and return single word */ +- if (isquote(*current) && isquote(current[current_len - 1])) { +- char *tmp; +- +- tmp = strdup(current+1); +- if (!tmp) +- return NULL; +- tmp[strlen(tmp)-1] = '\0'; +- return tmp; +- } +- +- /* if no quotes, return second word verbatim */ +- if (!isquote(*current)) +- return current; +- +- /* second element start with a quote, so we have to find the element +- * whose last character is also quote (assuming it's the closing one) */ +- int resultMaxSize; +- char * result; +- /* need to ensure that ' does not match " as we search */ +- char quote_char = *current; +- +- resultMaxSize = sizeOfSingleLine(line); +- result = malloc(resultMaxSize); +- snprintf(result, resultMaxSize, "%s", ++current); +- +- i++; +- for (; i < line->numElements; ++i) { ++ i = 1; + current = line->elements[i].item; + current_len = strlen(current); +- current_indent = line->elements[i].indent; +- current_indent_len = strlen(current_indent); + +- strncat(result, current_indent, current_indent_len); +- if (current[current_len-1] != quote_char) { +- strncat(result, current, current_len); +- } else { +- strncat(result, current, current_len - 1); +- break; ++ /* if second word is quoted, strip the quotes and return single word */ ++ if (isquote(*current) && isquote(current[current_len - 1])) { ++ char *tmp; ++ ++ tmp = strdup(current + 1); ++ if (!tmp) ++ return NULL; ++ tmp[strlen(tmp) - 1] = '\0'; ++ return tmp; ++ } ++ ++ /* if no quotes, return second word verbatim */ ++ if (!isquote(*current)) ++ return current; ++ ++ /* second element start with a quote, so we have to find the element ++ * whose last character is also quote (assuming it's the closing one) */ ++ int resultMaxSize; ++ char *result; ++ /* need to ensure that ' does not match " as we search */ ++ char quote_char = *current; ++ ++ resultMaxSize = sizeOfSingleLine(line); ++ result = malloc(resultMaxSize); ++ snprintf(result, resultMaxSize, "%s", ++current); ++ ++ i++; ++ for (; i < line->numElements; ++i) { ++ current = line->elements[i].item; ++ current_len = strlen(current); ++ current_indent = line->elements[i].indent; ++ current_indent_len = strlen(current_indent); ++ ++ strncat(result, current_indent, current_indent_len); ++ if (current[current_len - 1] != quote_char) { ++ strncat(result, current, current_len); ++ } else { ++ strncat(result, current, current_len - 1); ++ break; ++ } + } +- } +- return result; ++ return result; + } + + struct configFileInfo grub2ConfigType = { +- .findConfig = grub2FindConfig, +- .getEnv = grub2GetEnv, +- .setEnv = grub2SetEnv, +- .keywords = grub2Keywords, +- .defaultIsIndex = 1, +- .defaultSupportSaved = 1, +- .defaultIsVariable = 1, +- .entryStart = LT_MENUENTRY, +- .entryEnd = LT_ENTRY_END, +- .titlePosition = 1, +- .needsBootPrefix = 1, +- .mbHyperFirst = 1, +- .mbInitRdIsModule = 1, +- .mbAllowExtraInitRds = 1, ++ .findConfig = grub2FindConfig, ++ .getEnv = grub2GetEnv, ++ .setEnv = grub2SetEnv, ++ .keywords = grub2Keywords, ++ .defaultIsIndex = 1, ++ .defaultSupportSaved = 1, ++ .defaultIsVariable = 1, ++ .entryStart = LT_MENUENTRY, ++ .entryEnd = LT_ENTRY_END, ++ .titlePosition = 1, ++ .needsBootPrefix = 1, ++ .mbHyperFirst = 1, ++ .mbInitRdIsModule = 1, ++ .mbAllowExtraInitRds = 1, + }; + + struct keywordTypes yabootKeywords[] = { +- { "label", LT_TITLE, '=' }, +- { "root", LT_ROOT, '=' }, +- { "default", LT_DEFAULT, '=' }, +- { "image", LT_KERNEL, '=' }, +- { "bsd", LT_GENERIC, '=' }, +- { "macos", LT_GENERIC, '=' }, +- { "macosx", LT_GENERIC, '=' }, +- { "magicboot", LT_GENERIC, '=' }, +- { "darwin", LT_GENERIC, '=' }, +- { "timeout", LT_GENERIC, '=' }, +- { "install", LT_GENERIC, '=' }, +- { "fstype", LT_GENERIC, '=' }, +- { "hfstype", LT_GENERIC, '=' }, +- { "delay", LT_GENERIC, '=' }, +- { "defaultos", LT_GENERIC, '=' }, +- { "init-message", LT_GENERIC, '=' }, +- { "enablecdboot", LT_GENERIC, ' ' }, +- { "enableofboot", LT_GENERIC, ' ' }, +- { "enablenetboot", LT_GENERIC, ' ' }, +- { "nonvram", LT_GENERIC, ' ' }, +- { "hide", LT_GENERIC, ' ' }, +- { "protect", LT_GENERIC, ' ' }, +- { "nobless", LT_GENERIC, ' ' }, +- { "nonvram", LT_GENERIC, ' ' }, +- { "brokenosx", LT_GENERIC, ' ' }, +- { "usemount", LT_GENERIC, ' ' }, +- { "mntpoint", LT_GENERIC, '=' }, +- { "partition", LT_GENERIC, '=' }, +- { "device", LT_GENERIC, '=' }, +- { "fstype", LT_GENERIC, '=' }, +- { "initrd", LT_INITRD, '=', ';' }, +- { "append", LT_KERNELARGS, '=' }, +- { "boot", LT_BOOT, '=' }, +- { "lba", LT_LBA, ' ' }, +- { NULL, 0, 0 }, ++ {"label", LT_TITLE, '='}, ++ {"root", LT_ROOT, '='}, ++ {"default", LT_DEFAULT, '='}, ++ {"image", LT_KERNEL, '='}, ++ {"bsd", LT_GENERIC, '='}, ++ {"macos", LT_GENERIC, '='}, ++ {"macosx", LT_GENERIC, '='}, ++ {"magicboot", LT_GENERIC, '='}, ++ {"darwin", LT_GENERIC, '='}, ++ {"timeout", LT_GENERIC, '='}, ++ {"install", LT_GENERIC, '='}, ++ {"fstype", LT_GENERIC, '='}, ++ {"hfstype", LT_GENERIC, '='}, ++ {"delay", LT_GENERIC, '='}, ++ {"defaultos", LT_GENERIC, '='}, ++ {"init-message", LT_GENERIC, '='}, ++ {"enablecdboot", LT_GENERIC, ' '}, ++ {"enableofboot", LT_GENERIC, ' '}, ++ {"enablenetboot", LT_GENERIC, ' '}, ++ {"nonvram", LT_GENERIC, ' '}, ++ {"hide", LT_GENERIC, ' '}, ++ {"protect", LT_GENERIC, ' '}, ++ {"nobless", LT_GENERIC, ' '}, ++ {"nonvram", LT_GENERIC, ' '}, ++ {"brokenosx", LT_GENERIC, ' '}, ++ {"usemount", LT_GENERIC, ' '}, ++ {"mntpoint", LT_GENERIC, '='}, ++ {"partition", LT_GENERIC, '='}, ++ {"device", LT_GENERIC, '='}, ++ {"fstype", LT_GENERIC, '='}, ++ {"initrd", LT_INITRD, '=', ';'}, ++ {"append", LT_KERNELARGS, '='}, ++ {"boot", LT_BOOT, '='}, ++ {"lba", LT_LBA, ' '}, ++ {NULL, 0, 0}, + }; + + struct keywordTypes liloKeywords[] = { +- { "label", LT_TITLE, '=' }, +- { "root", LT_ROOT, '=' }, +- { "default", LT_DEFAULT, '=' }, +- { "image", LT_KERNEL, '=' }, +- { "other", LT_OTHER, '=' }, +- { "initrd", LT_INITRD, '=' }, +- { "append", LT_KERNELARGS, '=' }, +- { "boot", LT_BOOT, '=' }, +- { "lba", LT_LBA, ' ' }, +- { NULL, 0, 0 }, ++ {"label", LT_TITLE, '='}, ++ {"root", LT_ROOT, '='}, ++ {"default", LT_DEFAULT, '='}, ++ {"image", LT_KERNEL, '='}, ++ {"other", LT_OTHER, '='}, ++ {"initrd", LT_INITRD, '='}, ++ {"append", LT_KERNELARGS, '='}, ++ {"boot", LT_BOOT, '='}, ++ {"lba", LT_LBA, ' '}, ++ {NULL, 0, 0}, + }; + + struct keywordTypes eliloKeywords[] = { +- { "label", LT_TITLE, '=' }, +- { "root", LT_ROOT, '=' }, +- { "default", LT_DEFAULT, '=' }, +- { "image", LT_KERNEL, '=' }, +- { "initrd", LT_INITRD, '=' }, +- { "append", LT_KERNELARGS, '=' }, +- { "vmm", LT_HYPER, '=' }, +- { NULL, 0, 0 }, ++ {"label", LT_TITLE, '='}, ++ {"root", LT_ROOT, '='}, ++ {"default", LT_DEFAULT, '='}, ++ {"image", LT_KERNEL, '='}, ++ {"initrd", LT_INITRD, '='}, ++ {"append", LT_KERNELARGS, '='}, ++ {"vmm", LT_HYPER, '='}, ++ {NULL, 0, 0}, + }; + + struct keywordTypes siloKeywords[] = { +- { "label", LT_TITLE, '=' }, +- { "root", LT_ROOT, '=' }, +- { "default", LT_DEFAULT, '=' }, +- { "image", LT_KERNEL, '=' }, +- { "other", LT_OTHER, '=' }, +- { "initrd", LT_INITRD, '=' }, +- { "append", LT_KERNELARGS, '=' }, +- { "boot", LT_BOOT, '=' }, +- { NULL, 0, 0 }, ++ {"label", LT_TITLE, '='}, ++ {"root", LT_ROOT, '='}, ++ {"default", LT_DEFAULT, '='}, ++ {"image", LT_KERNEL, '='}, ++ {"other", LT_OTHER, '='}, ++ {"initrd", LT_INITRD, '='}, ++ {"append", LT_KERNELARGS, '='}, ++ {"boot", LT_BOOT, '='}, ++ {NULL, 0, 0}, + }; + + struct keywordTypes ziplKeywords[] = { +- { "target", LT_BOOTROOT, '=' }, +- { "image", LT_KERNEL, '=' }, +- { "ramdisk", LT_INITRD, '=' }, +- { "parameters", LT_KERNELARGS, '=' }, +- { "default", LT_DEFAULT, '=' }, +- { NULL, 0, 0 }, ++ {"target", LT_BOOTROOT, '='}, ++ {"image", LT_KERNEL, '='}, ++ {"ramdisk", LT_INITRD, '='}, ++ {"parameters", LT_KERNELARGS, '='}, ++ {"default", LT_DEFAULT, '='}, ++ {NULL, 0, 0}, + }; + + struct keywordTypes extlinuxKeywords[] = { +- { "label", LT_TITLE, ' ' }, +- { "root", LT_ROOT, ' ' }, +- { "default", LT_DEFAULT, ' ' }, +- { "kernel", LT_KERNEL, ' ' }, +- { "initrd", LT_INITRD, ' ', ',' }, +- { "append", LT_KERNELARGS, ' ' }, +- { "prompt", LT_UNKNOWN, ' ' }, +- { NULL, 0, 0 }, ++ {"label", LT_TITLE, ' '}, ++ {"root", LT_ROOT, ' '}, ++ {"default", LT_DEFAULT, ' '}, ++ {"kernel", LT_KERNEL, ' '}, ++ {"initrd", LT_INITRD, ' ', ','}, ++ {"append", LT_KERNELARGS, ' '}, ++ {"prompt", LT_UNKNOWN, ' '}, ++ {NULL, 0, 0}, + }; ++ + int useextlinuxmenu; + struct configFileInfo eliloConfigType = { +- .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf", +- .keywords = eliloKeywords, +- .entryStart = LT_KERNEL, +- .needsBootPrefix = 1, +- .argsInQuotes = 1, +- .mbConcatArgs = 1, +- .titlePosition = 1, ++ .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf", ++ .keywords = eliloKeywords, ++ .entryStart = LT_KERNEL, ++ .needsBootPrefix = 1, ++ .argsInQuotes = 1, ++ .mbConcatArgs = 1, ++ .titlePosition = 1, + }; + + struct configFileInfo liloConfigType = { +- .defaultConfig = "/etc/lilo.conf", +- .keywords = liloKeywords, +- .entryStart = LT_KERNEL, +- .argsInQuotes = 1, +- .maxTitleLength = 15, +- .titlePosition = 1, ++ .defaultConfig = "/etc/lilo.conf", ++ .keywords = liloKeywords, ++ .entryStart = LT_KERNEL, ++ .argsInQuotes = 1, ++ .maxTitleLength = 15, ++ .titlePosition = 1, + }; + + struct configFileInfo yabootConfigType = { +- .defaultConfig = "/etc/yaboot.conf", +- .keywords = yabootKeywords, +- .entryStart = LT_KERNEL, +- .needsBootPrefix = 1, +- .argsInQuotes = 1, +- .maxTitleLength = 15, +- .mbAllowExtraInitRds = 1, +- .titlePosition = 1, ++ .defaultConfig = "/etc/yaboot.conf", ++ .keywords = yabootKeywords, ++ .entryStart = LT_KERNEL, ++ .needsBootPrefix = 1, ++ .argsInQuotes = 1, ++ .maxTitleLength = 15, ++ .mbAllowExtraInitRds = 1, ++ .titlePosition = 1, + }; + + struct configFileInfo siloConfigType = { +- .defaultConfig = "/etc/silo.conf", +- .keywords = siloKeywords, +- .entryStart = LT_KERNEL, +- .needsBootPrefix = 1, +- .argsInQuotes = 1, +- .maxTitleLength = 15, +- .titlePosition = 1, ++ .defaultConfig = "/etc/silo.conf", ++ .keywords = siloKeywords, ++ .entryStart = LT_KERNEL, ++ .needsBootPrefix = 1, ++ .argsInQuotes = 1, ++ .maxTitleLength = 15, ++ .titlePosition = 1, + }; + + struct configFileInfo ziplConfigType = { +- .defaultConfig = "/etc/zipl.conf", +- .keywords = ziplKeywords, +- .entryStart = LT_TITLE, +- .argsInQuotes = 1, +- .titleBracketed = 1, ++ .defaultConfig = "/etc/zipl.conf", ++ .keywords = ziplKeywords, ++ .entryStart = LT_TITLE, ++ .argsInQuotes = 1, ++ .titleBracketed = 1, + }; + + struct configFileInfo extlinuxConfigType = { +- .defaultConfig = "/boot/extlinux/extlinux.conf", +- .keywords = extlinuxKeywords, +- .caseInsensitive = 1, +- .entryStart = LT_TITLE, +- .needsBootPrefix = 1, +- .maxTitleLength = 255, +- .mbAllowExtraInitRds = 1, +- .defaultIsUnquoted = 1, +- .titlePosition = 1, ++ .defaultConfig = "/boot/extlinux/extlinux.conf", ++ .keywords = extlinuxKeywords, ++ .caseInsensitive = 1, ++ .entryStart = LT_TITLE, ++ .needsBootPrefix = 1, ++ .maxTitleLength = 255, ++ .mbAllowExtraInitRds = 1, ++ .defaultIsUnquoted = 1, ++ .titlePosition = 1, + }; + + struct grubConfig { +- struct singleLine * theLines; +- struct singleEntry * entries; +- char * primaryIndent; +- char * secondaryIndent; +- int defaultImage; /* -1 if none specified -- this value is +- * written out, overriding original */ +- int fallbackImage; /* just like defaultImage */ +- int flags; +- struct configFileInfo * cfi; ++ struct singleLine *theLines; ++ struct singleEntry *entries; ++ char *primaryIndent; ++ char *secondaryIndent; ++ int defaultImage; /* -1 if none specified -- this value is ++ * written out, overriding original */ ++ int fallbackImage; /* just like defaultImage */ ++ int flags; ++ struct configFileInfo *cfi; + }; + + blkid_cache blkid; + +-struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index); +-struct singleEntry * findEntryByPath(struct grubConfig * cfg, +- const char * path, const char * prefix, +- int * index); +-struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title, +- int * index); +-static int readFile(int fd, char ** bufPtr); +-static void lineInit(struct singleLine * line); +-struct singleLine * lineDup(struct singleLine * line); +-static void lineFree(struct singleLine * line); +-static int lineWrite(FILE * out, struct singleLine * line, +- struct configFileInfo * cfi); +-static int getNextLine(char ** bufPtr, struct singleLine * line, +- struct configFileInfo * cfi); +-static char * getRootSpecifier(char * str); +-static void requote(struct singleLine *line, struct configFileInfo * cfi); +-static void insertElement(struct singleLine * line, +- const char * item, int insertHere, +- struct configFileInfo * cfi); +-static void removeElement(struct singleLine * line, int removeHere); +-static struct keywordTypes * getKeywordByType(enum lineType_e type, +- struct configFileInfo * cfi); +-static enum lineType_e getTypeByKeyword(char * keyword, +- struct configFileInfo * cfi); +-static struct singleLine * getLineByType(enum lineType_e type, +- struct singleLine * line); +-static int checkForExtLinux(struct grubConfig * config); +-struct singleLine * addLineTmpl(struct singleEntry * entry, +- struct singleLine * tmplLine, +- struct singleLine * prevLine, +- const char * val, +- struct configFileInfo * cfi); +-struct singleLine * addLine(struct singleEntry * entry, +- struct configFileInfo * cfi, +- enum lineType_e type, char * defaultIndent, +- const char * val); +- +-static char * sdupprintf(const char *format, ...) ++struct singleEntry *findEntryByIndex(struct grubConfig *cfg, int index); ++struct singleEntry *findEntryByPath(struct grubConfig *cfg, ++ const char *path, const char *prefix, ++ int *index); ++struct singleEntry *findEntryByTitle(struct grubConfig *cfg, char *title, ++ int *index); ++static int readFile(int fd, char **bufPtr); ++static void lineInit(struct singleLine *line); ++struct singleLine *lineDup(struct singleLine *line); ++static void lineFree(struct singleLine *line); ++static int lineWrite(FILE * out, struct singleLine *line, ++ struct configFileInfo *cfi); ++static int getNextLine(char **bufPtr, struct singleLine *line, ++ struct configFileInfo *cfi); ++static char *getRootSpecifier(char *str); ++static void requote(struct singleLine *line, struct configFileInfo *cfi); ++static void insertElement(struct singleLine *line, ++ const char *item, int insertHere, ++ struct configFileInfo *cfi); ++static void removeElement(struct singleLine *line, int removeHere); ++static struct keywordTypes *getKeywordByType(enum lineType_e type, ++ struct configFileInfo *cfi); ++static enum lineType_e getTypeByKeyword(char *keyword, ++ struct configFileInfo *cfi); ++static struct singleLine *getLineByType(enum lineType_e type, ++ struct singleLine *line); ++static int checkForExtLinux(struct grubConfig *config); ++struct singleLine *addLineTmpl(struct singleEntry *entry, ++ struct singleLine *tmplLine, ++ struct singleLine *prevLine, ++ const char *val, struct configFileInfo *cfi); ++struct singleLine *addLine(struct singleEntry *entry, ++ struct configFileInfo *cfi, ++ enum lineType_e type, char *defaultIndent, ++ const char *val); ++ ++static char *sdupprintf(const char *format, ...) + #ifdef __GNUC__ +- __attribute__ ((format (printf, 1, 2))); ++ __attribute__ ((format(printf, 1, 2))); + #else +- ; ++; + #endif + +-static char * sdupprintf(const char *format, ...) { +- char *buf = NULL; +- char c; +- va_list args; +- size_t size = 0; +- va_start(args, format); +- +- /* XXX requires C99 vsnprintf behavior */ +- size = vsnprintf(&c, 1, format, args) + 1; +- if (size == -1) { +- printf("ERROR: vsnprintf behavior is not C99\n"); +- abort(); +- } +- +- va_end(args); +- va_start(args, format); +- +- buf = malloc(size); +- if (buf == NULL) +- return NULL; +- vsnprintf(buf, size, format, args); +- va_end (args); ++static char *sdupprintf(const char *format, ...) ++{ ++ char *buf = NULL; ++ char c; ++ va_list args; ++ size_t size = 0; ++ va_start(args, format); ++ ++ /* XXX requires C99 vsnprintf behavior */ ++ size = vsnprintf(&c, 1, format, args) + 1; ++ if (size == -1) { ++ printf("ERROR: vsnprintf behavior is not C99\n"); ++ abort(); ++ } + +- return buf; ++ va_end(args); ++ va_start(args, format); ++ ++ buf = malloc(size); ++ if (buf == NULL) ++ return NULL; ++ vsnprintf(buf, size, format, args); ++ va_end(args); ++ ++ return buf; + } + + static enum lineType_e preferredLineType(enum lineType_e type, +- struct configFileInfo *cfi) { +- if (isEfi && cfi == &grub2ConfigType) { +- switch (type) { +- case LT_KERNEL: +- return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI; +- case LT_INITRD: +- return isEfiOnly ? LT_INITRD : LT_INITRD_EFI; +- default: +- return type; +- } ++ struct configFileInfo *cfi) ++{ ++ if (isEfi && cfi == &grub2ConfigType) { ++ switch (type) { ++ case LT_KERNEL: ++ return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI; ++ case LT_INITRD: ++ return isEfiOnly ? LT_INITRD : LT_INITRD_EFI; ++ default: ++ return type; ++ } + #if defined(__i386__) || defined(__x86_64__) +- } else if (cfi == &grub2ConfigType) { +- switch (type) { +- case LT_KERNEL: +- return LT_KERNEL_16; +- case LT_INITRD: +- return LT_INITRD_16; +- default: +- return type; +- } ++ } else if (cfi == &grub2ConfigType) { ++ switch (type) { ++ case LT_KERNEL: ++ return LT_KERNEL_16; ++ case LT_INITRD: ++ return LT_INITRD_16; ++ default: ++ return type; ++ } + #endif +- } +- return type; ++ } ++ return type; + } + +-static struct keywordTypes * getKeywordByType(enum lineType_e type, +- struct configFileInfo * cfi) { +- for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) { +- if (kw->type == type) +- return kw; +- } +- return NULL; ++static struct keywordTypes *getKeywordByType(enum lineType_e type, ++ struct configFileInfo *cfi) ++{ ++ for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) { ++ if (kw->type == type) ++ return kw; ++ } ++ return NULL; + } + +-static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) { +- struct keywordTypes *kt = getKeywordByType(type, cfi); +- if (kt) +- return kt->key; +- return "unknown"; ++static char *getKeyByType(enum lineType_e type, struct configFileInfo *cfi) ++{ ++ struct keywordTypes *kt = getKeywordByType(type, cfi); ++ if (kt) ++ return kt->key; ++ return "unknown"; + } + +-static char * getpathbyspec(char *device) { +- if (!blkid) +- blkid_get_cache(&blkid, NULL); ++static char *getpathbyspec(char *device) ++{ ++ if (!blkid) ++ blkid_get_cache(&blkid, NULL); + +- return blkid_get_devname(blkid, device, NULL); ++ return blkid_get_devname(blkid, device, NULL); + } + +-static char * getuuidbydev(char *device) { +- if (!blkid) +- blkid_get_cache(&blkid, NULL); ++static char *getuuidbydev(char *device) ++{ ++ if (!blkid) ++ blkid_get_cache(&blkid, NULL); + +- return blkid_get_tag_value(blkid, "UUID", device); ++ return blkid_get_tag_value(blkid, "UUID", device); + } + +-static enum lineType_e getTypeByKeyword(char * keyword, +- struct configFileInfo * cfi) { +- for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) { +- if (cfi->caseInsensitive) { +- if (!strcasecmp(keyword, kw->key)) +- return kw->type; +- } else { +- if (!strcmp(keyword, kw->key)) +- return kw->type; ++static enum lineType_e getTypeByKeyword(char *keyword, ++ struct configFileInfo *cfi) ++{ ++ for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) { ++ if (cfi->caseInsensitive) { ++ if (!strcasecmp(keyword, kw->key)) ++ return kw->type; ++ } else { ++ if (!strcmp(keyword, kw->key)) ++ return kw->type; ++ } + } +- } +- return LT_UNKNOWN; ++ return LT_UNKNOWN; + } + +-static struct singleLine * getLineByType(enum lineType_e type, +- struct singleLine * line) { +- dbgPrintf("getLineByType(%d): ", type); +- for (; line; line = line->next) { +- dbgPrintf("%d:%s ", line->type, +- line->numElements ? line->elements[0].item : "(empty)"); +- if (line->type & type) break; +- } +- dbgPrintf(line ? "\n" : " (failed)\n"); +- return line; ++static struct singleLine *getLineByType(enum lineType_e type, ++ struct singleLine *line) ++{ ++ dbgPrintf("getLineByType(%d): ", type); ++ for (; line; line = line->next) { ++ dbgPrintf("%d:%s ", line->type, ++ line->numElements ? line->elements[0]. ++ item : "(empty)"); ++ if (line->type & type) ++ break; ++ } ++ dbgPrintf(line ? "\n" : " (failed)\n"); ++ return line; + } + +-static int isBracketedTitle(struct singleLine * line) { +- if (line->numElements == 1 && *line->elements[0].item == '[') { +- int len = strlen(line->elements[0].item); +- if (*(line->elements[0].item + len - 1) == ']') { +- /* FIXME: this is a hack... */ +- if (strcmp(line->elements[0].item, "[defaultboot]")) { +- return 1; +- } +- } +- } +- return 0; ++static int isBracketedTitle(struct singleLine *line) ++{ ++ if (line->numElements == 1 && *line->elements[0].item == '[') { ++ int len = strlen(line->elements[0].item); ++ if (*(line->elements[0].item + len - 1) == ']') { ++ /* FIXME: this is a hack... */ ++ if (strcmp(line->elements[0].item, "[defaultboot]")) { ++ return 1; ++ } ++ } ++ } ++ return 0; + } + +-static int isEntryStart(struct singleLine * line, +- struct configFileInfo * cfi) { +- return line->type == cfi->entryStart || line->type == LT_OTHER || +- (cfi->titleBracketed && isBracketedTitle(line)); ++static int isEntryStart(struct singleLine *line, struct configFileInfo *cfi) ++{ ++ return line->type == cfi->entryStart || line->type == LT_OTHER || ++ (cfi->titleBracketed && isBracketedTitle(line)); + } + + /* extract the title from within brackets (for zipl) */ +-static char * extractTitle(struct grubConfig *cfg, struct singleLine * line) { +- /* bracketed title... let's extract it */ +- char * title = NULL; +- if (line->type == LT_TITLE) { +- char *tmp = line->elements[cfg->cfi->titlePosition].item; +- if (cfg->cfi->titleBracketed) { +- tmp++; +- title = strdup(tmp); +- *(title + strlen(title) - 1) = '\0'; +- } else { +- title = strdup(tmp); +- } +- } else if (line->type == LT_MENUENTRY) +- title = strdup(line->elements[1].item); +- else +- return NULL; +- return title; ++static char *extractTitle(struct grubConfig *cfg, struct singleLine *line) ++{ ++ /* bracketed title... let's extract it */ ++ char *title = NULL; ++ if (line->type == LT_TITLE) { ++ char *tmp = line->elements[cfg->cfi->titlePosition].item; ++ if (cfg->cfi->titleBracketed) { ++ tmp++; ++ title = strdup(tmp); ++ *(title + strlen(title) - 1) = '\0'; ++ } else { ++ title = strdup(tmp); ++ } ++ } else if (line->type == LT_MENUENTRY) ++ title = strdup(line->elements[1].item); ++ else ++ return NULL; ++ return title; + } + +-static int readFile(int fd, char ** bufPtr) { +- int alloced = 0, size = 0, i = 0; +- char * buf = NULL; ++static int readFile(int fd, char **bufPtr) ++{ ++ int alloced = 0, size = 0, i = 0; ++ char *buf = NULL; ++ ++ do { ++ size += i; ++ if ((size + 1024) > alloced) { ++ alloced += 4096; ++ buf = realloc(buf, alloced + 1); ++ } ++ } while ((i = read(fd, buf + size, 1024)) > 0); + +- do { +- size += i; +- if ((size + 1024) > alloced) { +- alloced += 4096; +- buf = realloc(buf, alloced + 1); ++ if (i < 0) { ++ fprintf(stderr, _("error reading input: %s\n"), ++ strerror(errno)); ++ free(buf); ++ return 1; + } +- } while ((i = read(fd, buf + size, 1024)) > 0); +- +- if (i < 0) { +- fprintf(stderr, _("error reading input: %s\n"), strerror(errno)); +- free(buf); +- return 1; +- } + +- buf = realloc(buf, size + 2); +- if (size == 0) +- buf[size++] = '\n'; +- else +- if (buf[size - 1] != '\n') +- buf[size++] = '\n'; +- buf[size] = '\0'; ++ buf = realloc(buf, size + 2); ++ if (size == 0) ++ buf[size++] = '\n'; ++ else if (buf[size - 1] != '\n') ++ buf[size++] = '\n'; ++ buf[size] = '\0'; + +- *bufPtr = buf; ++ *bufPtr = buf; + +- return 0; ++ return 0; + } + +-static void lineInit(struct singleLine * line) { +- line->indent = NULL; +- line->elements = NULL; +- line->numElements = 0; +- line->next = NULL; ++static void lineInit(struct singleLine *line) ++{ ++ line->indent = NULL; ++ line->elements = NULL; ++ line->numElements = 0; ++ line->next = NULL; + } + +-struct singleLine * lineDup(struct singleLine * line) { +- struct singleLine * newLine = malloc(sizeof(*newLine)); +- +- newLine->indent = strdup(line->indent); +- newLine->next = NULL; +- newLine->type = line->type; +- newLine->numElements = line->numElements; +- newLine->elements = malloc(sizeof(*newLine->elements) * +- newLine->numElements); +- +- for (int i = 0; i < newLine->numElements; i++) { +- newLine->elements[i].indent = strdup(line->elements[i].indent); +- newLine->elements[i].item = strdup(line->elements[i].item); +- } ++struct singleLine *lineDup(struct singleLine *line) ++{ ++ struct singleLine *newLine = malloc(sizeof(*newLine)); ++ ++ newLine->indent = strdup(line->indent); ++ newLine->next = NULL; ++ newLine->type = line->type; ++ newLine->numElements = line->numElements; ++ newLine->elements = malloc(sizeof(*newLine->elements) * ++ newLine->numElements); ++ ++ for (int i = 0; i < newLine->numElements; i++) { ++ newLine->elements[i].indent = strdup(line->elements[i].indent); ++ newLine->elements[i].item = strdup(line->elements[i].item); ++ } + +- return newLine; ++ return newLine; + } + +-static void lineFree(struct singleLine * line) { +- if (line->indent) free(line->indent); ++static void lineFree(struct singleLine *line) ++{ ++ if (line->indent) ++ free(line->indent); + +- for (int i = 0; i < line->numElements; i++) { +- free(line->elements[i].item); +- free(line->elements[i].indent); +- } ++ for (int i = 0; i < line->numElements; i++) { ++ free(line->elements[i].item); ++ free(line->elements[i].indent); ++ } + +- if (line->elements) free(line->elements); +- lineInit(line); ++ if (line->elements) ++ free(line->elements); ++ lineInit(line); + } + +-static int lineWrite(FILE * out, struct singleLine * line, +- struct configFileInfo * cfi) { +- if (fprintf(out, "%s", line->indent) == -1) return -1; +- +- for (int i = 0; i < line->numElements; i++) { +- /* Need to handle this, because we strip the quotes from +- * menuentry when read it. */ +- if (line->type == LT_MENUENTRY && i == 1) { +- if(!isquote(*line->elements[i].item)) { +- int substring = 0; +- /* If the line contains nested quotes, we did not strip +- * the "interna" quotes and we must use the right quotes +- * again when writing the updated file. */ +- for (int j = i; j < line->numElements; j++) { +- if (strchr(line->elements[i].item, '\'') != NULL) { +- substring = 1; +- fprintf(out, "\"%s\"", line->elements[i].item); +- break; +- } +- } +- if (!substring) +- fprintf(out, "\'%s\'", line->elements[i].item); +- } else { +- fprintf(out, "%s", line->elements[i].item); +- } +- fprintf(out, "%s", line->elements[i].indent); ++static int lineWrite(FILE * out, struct singleLine *line, ++ struct configFileInfo *cfi) ++{ ++ if (fprintf(out, "%s", line->indent) == -1) ++ return -1; ++ ++ for (int i = 0; i < line->numElements; i++) { ++ /* Need to handle this, because we strip the quotes from ++ * menuentry when read it. */ ++ if (line->type == LT_MENUENTRY && i == 1) { ++ if (!isquote(*line->elements[i].item)) { ++ int substring = 0; ++ /* If the line contains nested quotes, we did not strip ++ * the "interna" quotes and we must use the right quotes ++ * again when writing the updated file. */ ++ for (int j = i; j < line->numElements; j++) { ++ if (strchr(line->elements[i].item, '\'') ++ != NULL) { ++ substring = 1; ++ fprintf(out, "\"%s\"", ++ line->elements[i].item); ++ break; ++ } ++ } ++ if (!substring) ++ fprintf(out, "\'%s\'", ++ line->elements[i].item); ++ } else { ++ fprintf(out, "%s", line->elements[i].item); ++ } ++ fprintf(out, "%s", line->elements[i].indent); + +- continue; +- } ++ continue; ++ } + +- if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes) +- if (fputc('"', out) == EOF) return -1; ++ if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes) ++ if (fputc('"', out) == EOF) ++ return -1; + +- if (fprintf(out, "%s", line->elements[i].item) == -1) return -1; +- if (i < line->numElements - 1) +- if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1; +- } ++ if (fprintf(out, "%s", line->elements[i].item) == -1) ++ return -1; ++ if (i < line->numElements - 1) ++ if (fprintf(out, "%s", line->elements[i].indent) == -1) ++ return -1; ++ } + +- if (line->type == LT_KERNELARGS && cfi->argsInQuotes) +- if (fputc('"', out) == EOF) return -1; ++ if (line->type == LT_KERNELARGS && cfi->argsInQuotes) ++ if (fputc('"', out) == EOF) ++ return -1; + +- if (fprintf(out, "\n") == -1) return -1; ++ if (fprintf(out, "\n") == -1) ++ return -1; + +- return 0; ++ return 0; + } + + /* we've guaranteed that the buffer ends w/ \n\0 */ +-static int getNextLine(char ** bufPtr, struct singleLine * line, +- struct configFileInfo * cfi) { +- char * end; +- char * start = *bufPtr; +- char * chptr; +- int elementsAlloced = 0; +- struct lineElement * element; +- int first = 1; +- +- lineFree(line); ++static int getNextLine(char **bufPtr, struct singleLine *line, ++ struct configFileInfo *cfi) ++{ ++ char *end; ++ char *start = *bufPtr; ++ char *chptr; ++ int elementsAlloced = 0; ++ struct lineElement *element; ++ int first = 1; + +- end = strchr(start, '\n'); +- *end = '\0'; +- *bufPtr = end + 1; ++ lineFree(line); + +- for (chptr = start; *chptr && isspace(*chptr); chptr++) ; ++ end = strchr(start, '\n'); ++ *end = '\0'; ++ *bufPtr = end + 1; + +- line->indent = strndup(start, chptr - start); +- start = chptr; ++ for (chptr = start; *chptr && isspace(*chptr); chptr++) ; + +- while (start < end) { +- /* we know !isspace(*start) */ ++ line->indent = strndup(start, chptr - start); ++ start = chptr; + +- if (elementsAlloced == line->numElements) { +- elementsAlloced += 5; +- line->elements = realloc(line->elements, +- sizeof(*line->elements) * elementsAlloced); +- } ++ while (start < end) { ++ /* we know !isspace(*start) */ + +- element = line->elements + line->numElements; ++ if (elementsAlloced == line->numElements) { ++ elementsAlloced += 5; ++ line->elements = realloc(line->elements, ++ sizeof(*line->elements) * ++ elementsAlloced); ++ } + +- chptr = start; +- while (*chptr && !isspace(*chptr)) { +- if (first && *chptr == '=') break; +- chptr++; +- } +- element->item = strndup(start, chptr - start); +- start = chptr; ++ element = line->elements + line->numElements; + +- /* lilo actually accepts the pathological case of append = " foo " */ +- if (*start == '=') +- chptr = start + 1; +- else +- chptr = start; ++ chptr = start; ++ while (*chptr && !isspace(*chptr)) { ++ if (first && *chptr == '=') ++ break; ++ chptr++; ++ } ++ element->item = strndup(start, chptr - start); ++ start = chptr; + +- do { +- for (; *chptr && isspace(*chptr); chptr++); +- if (*chptr == '=') +- chptr = chptr + 1; +- } while (isspace(*chptr)); ++ /* lilo actually accepts the pathological case of append = " foo " */ ++ if (*start == '=') ++ chptr = start + 1; ++ else ++ chptr = start; + +- element->indent = strndup(start, chptr - start); +- start = chptr; ++ do { ++ for (; *chptr && isspace(*chptr); chptr++) ; ++ if (*chptr == '=') ++ chptr = chptr + 1; ++ } while (isspace(*chptr)); + +- line->numElements++; +- first = 0; +- } +- +- if (!line->numElements) +- line->type = LT_WHITESPACE; +- else { +- line->type = getTypeByKeyword(line->elements[0].item, cfi); +- if (line->type == LT_UNKNOWN) { +- /* zipl does [title] instead of something reasonable like all +- * the other boot loaders. kind of ugly */ +- if (cfi->titleBracketed && isBracketedTitle(line)) { +- line->type = LT_TITLE; +- } +- +- /* this is awkward, but we need to be able to handle keywords +- that begin with a # (specifically for #boot in grub.conf), +- but still make comments lines with no elements (everything +- stored in the indent */ +- if (*line->elements[0].item == '#') { +- char * fullLine; +- int len; +- +- len = strlen(line->indent); +- for (int i = 0; i < line->numElements; i++) +- len += strlen(line->elements[i].item) + +- strlen(line->elements[i].indent); +- +- fullLine = malloc(len + 1); +- strcpy(fullLine, line->indent); +- free(line->indent); +- line->indent = fullLine; ++ element->indent = strndup(start, chptr - start); ++ start = chptr; + +- for (int i = 0; i < line->numElements; i++) { +- strcat(fullLine, line->elements[i].item); +- strcat(fullLine, line->elements[i].indent); +- free(line->elements[i].item); +- free(line->elements[i].indent); +- } ++ line->numElements++; ++ first = 0; ++ } + ++ if (!line->numElements) + line->type = LT_WHITESPACE; +- line->numElements = 0; +- } +- } else { +- struct keywordTypes *kw; ++ else { ++ line->type = getTypeByKeyword(line->elements[0].item, cfi); ++ if (line->type == LT_UNKNOWN) { ++ /* zipl does [title] instead of something reasonable like all ++ * the other boot loaders. kind of ugly */ ++ if (cfi->titleBracketed && isBracketedTitle(line)) { ++ line->type = LT_TITLE; ++ } + +- kw = getKeywordByType(line->type, cfi); ++ /* this is awkward, but we need to be able to handle keywords ++ that begin with a # (specifically for #boot in grub.conf), ++ but still make comments lines with no elements (everything ++ stored in the indent */ ++ if (*line->elements[0].item == '#') { ++ char *fullLine; ++ int len; ++ ++ len = strlen(line->indent); ++ for (int i = 0; i < line->numElements; i++) ++ len += strlen(line->elements[i].item) + ++ strlen(line->elements[i].indent); ++ ++ fullLine = malloc(len + 1); ++ strcpy(fullLine, line->indent); ++ free(line->indent); ++ line->indent = fullLine; ++ ++ for (int i = 0; i < line->numElements; i++) { ++ strcat(fullLine, ++ line->elements[i].item); ++ strcat(fullLine, ++ line->elements[i].indent); ++ free(line->elements[i].item); ++ free(line->elements[i].indent); ++ } + +- /* space isn't the only separator, we need to split +- * elements up more +- */ +- if (!isspace(kw->separatorChar)) { +- char indent[2] = ""; +- indent[0] = kw->separatorChar; +- for (int i = 1; i < line->numElements; i++) { +- char *p; +- int numNewElements; +- +- numNewElements = 0; +- p = line->elements[i].item; +- while (*p != '\0') { +- if (*p == kw->separatorChar) +- numNewElements++; +- p++; +- } +- if (line->numElements + numNewElements >= elementsAlloced) { +- elementsAlloced += numNewElements + 5; +- line->elements = realloc(line->elements, +- sizeof(*line->elements) * elementsAlloced); ++ line->type = LT_WHITESPACE; ++ line->numElements = 0; + } ++ } else { ++ struct keywordTypes *kw; + +- for (int j = line->numElements; j > i; j--) { +- line->elements[j + numNewElements] = line->elements[j]; +- } +- line->numElements += numNewElements; ++ kw = getKeywordByType(line->type, cfi); + +- p = line->elements[i].item; +- while (*p != '\0') { ++ /* space isn't the only separator, we need to split ++ * elements up more ++ */ ++ if (!isspace(kw->separatorChar)) { ++ char indent[2] = ""; ++ indent[0] = kw->separatorChar; ++ for (int i = 1; i < line->numElements; i++) { ++ char *p; ++ int numNewElements; ++ ++ numNewElements = 0; ++ p = line->elements[i].item; ++ while (*p != '\0') { ++ if (*p == kw->separatorChar) ++ numNewElements++; ++ p++; ++ } ++ if (line->numElements + ++ numNewElements >= elementsAlloced) { ++ elementsAlloced += ++ numNewElements + 5; ++ line->elements = ++ realloc(line->elements, ++ sizeof(*line-> ++ elements) * ++ elementsAlloced); ++ } + +- while (*p != kw->separatorChar && *p != '\0') p++; +- if (*p == '\0') { +- break; ++ for (int j = line->numElements; j > i; ++ j--) { ++ line->elements[j + ++ numNewElements] = ++ line->elements[j]; ++ } ++ line->numElements += numNewElements; ++ ++ p = line->elements[i].item; ++ while (*p != '\0') { ++ ++ while (*p != kw->separatorChar ++ && *p != '\0') ++ p++; ++ if (*p == '\0') { ++ break; ++ } ++ ++ line->elements[i + 1].indent = ++ line->elements[i].indent; ++ line->elements[i].indent = ++ strdup(indent); ++ *p++ = '\0'; ++ i++; ++ line->elements[i].item = ++ strdup(p); ++ } + } +- +- line->elements[i + 1].indent = line->elements[i].indent; +- line->elements[i].indent = strdup(indent); +- *p++ = '\0'; +- i++; +- line->elements[i].item = strdup(p); + } +- } + } + } +- } + +- return 0; ++ return 0; + } + + static int isnumber(const char *s) + { +- int i; +- for (i = 0; s[i] != '\0'; i++) +- if (s[i] < '0' || s[i] > '9') +- return 0; +- return i; ++ int i; ++ for (i = 0; s[i] != '\0'; i++) ++ if (s[i] < '0' || s[i] > '9') ++ return 0; ++ return i; + } + +-static struct grubConfig * readConfig(const char * inName, +- struct configFileInfo * cfi) { +- int in; +- char * incoming = NULL, * head; +- int rc; +- int sawEntry = 0; +- int movedLine = 0; +- struct grubConfig * cfg; +- struct singleLine * last = NULL, * line, * defaultLine = NULL; +- char * end; +- struct singleEntry * entry = NULL; +- int len; +- char * buf; +- +- if (inName == NULL) { +- printf("Could not find bootloader configuration\n"); +- exit(1); +- } else if (!strcmp(inName, "-")) { +- in = 0; +- } else { +- if ((in = open(inName, O_RDONLY)) < 0) { +- fprintf(stderr, _("error opening %s for read: %s\n"), +- inName, strerror(errno)); +- return NULL; +- } +- } +- +- rc = readFile(in, &incoming); +- close(in); +- if (rc) return NULL; +- +- head = incoming; +- cfg = malloc(sizeof(*cfg)); +- cfg->primaryIndent = strdup(""); +- cfg->secondaryIndent = strdup("\t"); +- cfg->flags = GRUB_CONFIG_NO_DEFAULT; +- cfg->cfi = cfi; +- cfg->theLines = NULL; +- cfg->entries = NULL; +- cfg->fallbackImage = 0; +- +- /* copy everything we have */ +- while (*head) { +- line = malloc(sizeof(*line)); +- lineInit(line); +- +- if (getNextLine(&head, line, cfi)) { +- free(line); +- /* XXX memory leak of everything in cfg */ +- return NULL; +- } +- +- if (!sawEntry && line->numElements) { +- free(cfg->primaryIndent); +- cfg->primaryIndent = strdup(line->indent); +- } else if (line->numElements) { +- free(cfg->secondaryIndent); +- cfg->secondaryIndent = strdup(line->indent); ++static struct grubConfig *readConfig(const char *inName, ++ struct configFileInfo *cfi) ++{ ++ int in; ++ char *incoming = NULL, *head; ++ int rc; ++ int sawEntry = 0; ++ int movedLine = 0; ++ struct grubConfig *cfg; ++ struct singleLine *last = NULL, *line, *defaultLine = NULL; ++ char *end; ++ struct singleEntry *entry = NULL; ++ int len; ++ char *buf; ++ ++ if (inName == NULL) { ++ printf("Could not find bootloader configuration\n"); ++ exit(1); ++ } else if (!strcmp(inName, "-")) { ++ in = 0; ++ } else { ++ if ((in = open(inName, O_RDONLY)) < 0) { ++ fprintf(stderr, _("error opening %s for read: %s\n"), ++ inName, strerror(errno)); ++ return NULL; ++ } + } + +- if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) { +- sawEntry = 1; +- if (!entry) { +- cfg->entries = malloc(sizeof(*entry)); +- entry = cfg->entries; +- } else { +- entry->next = malloc(sizeof(*entry)); +- entry = entry->next; +- } +- +- entry->skip = 0; +- entry->multiboot = 0; +- entry->lines = NULL; +- entry->next = NULL; +- } +- +- if (line->type == LT_SET_VARIABLE) { +- dbgPrintf("found 'set' command (%d elements): ", line->numElements); +- dbgPrintf("%s", line->indent); +- for (int i = 0; i < line->numElements; i++) +- dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent); +- dbgPrintf("\n"); +- struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi); +- if (kwType && line->numElements == 3 && +- !strcmp(line->elements[1].item, kwType->key) && +- !is_special_grub2_variable(line->elements[2].item)) { +- dbgPrintf("Line sets default config\n"); +- cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; +- defaultLine = line; +- } +- +- } else if (iskernel(line->type)) { +- /* if by some freak chance this is multiboot and the "module" +- * lines came earlier in the template, make sure to use LT_HYPER +- * instead of LT_KERNEL now +- */ +- if (entry && entry->multiboot) +- line->type = LT_HYPER; +- +- } else if (line->type == LT_MBMODULE) { +- /* go back and fix the LT_KERNEL line to indicate LT_HYPER +- * instead, now that we know this is a multiboot entry. +- * This only applies to grub, but that's the only place we +- * should find LT_MBMODULE lines anyway. +- */ +- for (struct singleLine *l = entry->lines; l; l = l->next) { +- if (l->type == LT_HYPER) +- break; +- else if (iskernel(l->type)) { +- l->type = LT_HYPER; +- break; ++ rc = readFile(in, &incoming); ++ close(in); ++ if (rc) ++ return NULL; ++ ++ head = incoming; ++ cfg = malloc(sizeof(*cfg)); ++ cfg->primaryIndent = strdup(""); ++ cfg->secondaryIndent = strdup("\t"); ++ cfg->flags = GRUB_CONFIG_NO_DEFAULT; ++ cfg->cfi = cfi; ++ cfg->theLines = NULL; ++ cfg->entries = NULL; ++ cfg->fallbackImage = 0; ++ ++ /* copy everything we have */ ++ while (*head) { ++ line = malloc(sizeof(*line)); ++ lineInit(line); ++ ++ if (getNextLine(&head, line, cfi)) { ++ free(line); ++ /* XXX memory leak of everything in cfg */ ++ return NULL; + } +- } +- entry->multiboot = 1; +- +- } else if (line->type == LT_HYPER) { +- entry->multiboot = 1; +- +- } else if (line->type == LT_FALLBACK && line->numElements == 2) { +- cfg->fallbackImage = strtol(line->elements[1].item, &end, 10); +- if (*end) cfg->fallbackImage = -1; +- +- } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) || +- (line->type == LT_TITLE && line->numElements > 1)) { +- /* make the title/default a single argument (undoing our parsing) */ +- len = 0; +- for (int i = 1; i < line->numElements; i++) { +- len += strlen(line->elements[i].item); +- len += strlen(line->elements[i].indent); +- } +- buf = malloc(len + 1); +- *buf = '\0'; +- +- for (int i = 1; i < line->numElements; i++) { +- strcat(buf, line->elements[i].item); +- free(line->elements[i].item); + +- if ((i + 1) != line->numElements) { +- strcat(buf, line->elements[i].indent); +- free(line->elements[i].indent); +- } +- } +- +- line->elements[1].indent = +- line->elements[line->numElements - 1].indent; +- line->elements[1].item = buf; +- line->numElements = 2; +- } else if (line->type == LT_MENUENTRY && line->numElements > 3) { +- /* let --remove-kernel="TITLE=what" work */ +- len = 0; +- char *extras; +- char *title; +- /* initially unseen value */ +- char quote_char = '\0'; +- +- for (int i = 1; i < line->numElements; i++) { +- len += strlen(line->elements[i].item); +- len += strlen(line->elements[i].indent); +- } +- buf = malloc(len + 1); +- *buf = '\0'; +- +- /* allocate mem for extra flags. */ +- extras = malloc(len + 1); +- *extras = '\0'; +- +- /* get title. */ +- for (int i = 0; i < line->numElements; i++) { +- if (!strcmp(line->elements[i].item, "menuentry")) +- continue; +- if (isquote(*line->elements[i].item) && quote_char == '\0') { +- /* ensure we properly pair off quotes */ +- quote_char = *line->elements[i].item; +- title = line->elements[i].item + 1; +- } else { +- title = line->elements[i].item; ++ if (!sawEntry && line->numElements) { ++ free(cfg->primaryIndent); ++ cfg->primaryIndent = strdup(line->indent); ++ } else if (line->numElements) { ++ free(cfg->secondaryIndent); ++ cfg->secondaryIndent = strdup(line->indent); + } + +- len = strlen(title); +- if (title[len-1] == quote_char) { +- strncat(buf, title,len-1); +- break; +- } else { +- strcat(buf, title); +- strcat(buf, line->elements[i].indent); +- } +- } +- +- /* get extras */ +- int count = 0; +- quote_char = '\0'; +- for (int i = 0; i < line->numElements; i++) { +- if (count >= 2) { +- strcat(extras, line->elements[i].item); +- strcat(extras, line->elements[i].indent); ++ if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) { ++ sawEntry = 1; ++ if (!entry) { ++ cfg->entries = malloc(sizeof(*entry)); ++ entry = cfg->entries; ++ } else { ++ entry->next = malloc(sizeof(*entry)); ++ entry = entry->next; ++ } ++ ++ entry->skip = 0; ++ entry->multiboot = 0; ++ entry->lines = NULL; ++ entry->next = NULL; + } + +- if (!strcmp(line->elements[i].item, "menuentry")) +- continue; ++ if (line->type == LT_SET_VARIABLE) { ++ dbgPrintf("found 'set' command (%d elements): ", ++ line->numElements); ++ dbgPrintf("%s", line->indent); ++ for (int i = 0; i < line->numElements; i++) ++ dbgPrintf("\"%s\"%s", line->elements[i].item, ++ line->elements[i].indent); ++ dbgPrintf("\n"); ++ struct keywordTypes *kwType = ++ getKeywordByType(LT_DEFAULT, cfi); ++ if (kwType && line->numElements == 3 ++ && !strcmp(line->elements[1].item, kwType->key) ++ && !is_special_grub2_variable(line->elements[2]. ++ item)) { ++ dbgPrintf("Line sets default config\n"); ++ cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; ++ defaultLine = line; ++ } ++ ++ } else if (iskernel(line->type)) { ++ /* if by some freak chance this is multiboot and the "module" ++ * lines came earlier in the template, make sure to use LT_HYPER ++ * instead of LT_KERNEL now ++ */ ++ if (entry && entry->multiboot) ++ line->type = LT_HYPER; ++ ++ } else if (line->type == LT_MBMODULE) { ++ /* go back and fix the LT_KERNEL line to indicate LT_HYPER ++ * instead, now that we know this is a multiboot entry. ++ * This only applies to grub, but that's the only place we ++ * should find LT_MBMODULE lines anyway. ++ */ ++ for (struct singleLine * l = entry->lines; l; ++ l = l->next) { ++ if (l->type == LT_HYPER) ++ break; ++ else if (iskernel(l->type)) { ++ l->type = LT_HYPER; ++ break; ++ } ++ } ++ entry->multiboot = 1; ++ ++ } else if (line->type == LT_HYPER) { ++ entry->multiboot = 1; ++ ++ } else if (line->type == LT_FALLBACK && line->numElements == 2) { ++ cfg->fallbackImage = ++ strtol(line->elements[1].item, &end, 10); ++ if (*end) ++ cfg->fallbackImage = -1; ++ ++ } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ++ || (line->type == LT_TITLE ++ && line->numElements > 1)) { ++ /* make the title/default a single argument (undoing our parsing) */ ++ len = 0; ++ for (int i = 1; i < line->numElements; i++) { ++ len += strlen(line->elements[i].item); ++ len += strlen(line->elements[i].indent); ++ } ++ buf = malloc(len + 1); ++ *buf = '\0'; ++ ++ for (int i = 1; i < line->numElements; i++) { ++ strcat(buf, line->elements[i].item); ++ free(line->elements[i].item); ++ ++ if ((i + 1) != line->numElements) { ++ strcat(buf, line->elements[i].indent); ++ free(line->elements[i].indent); ++ } ++ } ++ ++ line->elements[1].indent = ++ line->elements[line->numElements - 1].indent; ++ line->elements[1].item = buf; ++ line->numElements = 2; ++ } else if (line->type == LT_MENUENTRY && line->numElements > 3) { ++ /* let --remove-kernel="TITLE=what" work */ ++ len = 0; ++ char *extras; ++ char *title; ++ /* initially unseen value */ ++ char quote_char = '\0'; ++ ++ for (int i = 1; i < line->numElements; i++) { ++ len += strlen(line->elements[i].item); ++ len += strlen(line->elements[i].indent); ++ } ++ buf = malloc(len + 1); ++ *buf = '\0'; ++ ++ /* allocate mem for extra flags. */ ++ extras = malloc(len + 1); ++ *extras = '\0'; ++ ++ /* get title. */ ++ for (int i = 0; i < line->numElements; i++) { ++ if (!strcmp ++ (line->elements[i].item, "menuentry")) ++ continue; ++ if (isquote(*line->elements[i].item) ++ && quote_char == '\0') { ++ /* ensure we properly pair off quotes */ ++ quote_char = *line->elements[i].item; ++ title = line->elements[i].item + 1; ++ } else { ++ title = line->elements[i].item; ++ } ++ ++ len = strlen(title); ++ if (title[len - 1] == quote_char) { ++ strncat(buf, title, len - 1); ++ break; ++ } else { ++ strcat(buf, title); ++ strcat(buf, line->elements[i].indent); ++ } ++ } ++ ++ /* get extras */ ++ int count = 0; ++ quote_char = '\0'; ++ for (int i = 0; i < line->numElements; i++) { ++ if (count >= 2) { ++ strcat(extras, line->elements[i].item); ++ strcat(extras, ++ line->elements[i].indent); ++ } ++ ++ if (!strcmp ++ (line->elements[i].item, "menuentry")) ++ continue; + +- /* count ' or ", there should be two in menuentry line. */ +- if (isquote(*line->elements[i].item) && quote_char == '\0') { +- /* ensure we properly pair off quotes */ +- quote_char = *line->elements[i].item; +- count++; ++ /* count ' or ", there should be two in menuentry line. */ ++ if (isquote(*line->elements[i].item) ++ && quote_char == '\0') { ++ /* ensure we properly pair off quotes */ ++ quote_char = *line->elements[i].item; ++ count++; ++ } ++ ++ len = strlen(line->elements[i].item); ++ ++ if (line->elements[i].item[len - 1] == ++ quote_char) ++ count++; ++ ++ /* ok, we get the final ' or ", others are extras. */ ++ } ++ line->elements[1].indent = ++ line->elements[line->numElements - 2].indent; ++ line->elements[1].item = buf; ++ line->elements[2].indent = ++ line->elements[line->numElements - 2].indent; ++ line->elements[2].item = extras; ++ line->numElements = 3; ++ } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) { ++ /* Strip off any " which may be present; they'll be put back ++ on write. This is one of the few (the only?) places that grubby ++ canonicalizes the output */ ++ ++ if (line->numElements >= 2) { ++ int last, len; ++ ++ if (isquote(*line->elements[1].item)) ++ memmove(line->elements[1].item, ++ line->elements[1].item + 1, ++ strlen(line->elements[1].item + ++ 1) + 1); ++ ++ last = line->numElements - 1; ++ len = strlen(line->elements[last].item) - 1; ++ if (isquote(line->elements[last].item[len])) ++ line->elements[last].item[len] = '\0'; ++ } + } + +- len = strlen(line->elements[i].item); +- +- if (line->elements[i].item[len -1] == quote_char) +- count++; +- +- /* ok, we get the final ' or ", others are extras. */ +- } +- line->elements[1].indent = +- line->elements[line->numElements - 2].indent; +- line->elements[1].item = buf; +- line->elements[2].indent = +- line->elements[line->numElements - 2].indent; +- line->elements[2].item = extras; +- line->numElements = 3; +- } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) { +- /* Strip off any " which may be present; they'll be put back +- on write. This is one of the few (the only?) places that grubby +- canonicalizes the output */ +- +- if (line->numElements >= 2) { +- int last, len; +- +- if (isquote(*line->elements[1].item)) +- memmove(line->elements[1].item, line->elements[1].item + 1, +- strlen(line->elements[1].item + 1) + 1); +- +- last = line->numElements - 1; +- len = strlen(line->elements[last].item) - 1; +- if (isquote(line->elements[last].item[len])) +- line->elements[last].item[len] = '\0'; +- } +- } +- +- if (line->type == LT_DEFAULT && line->numElements == 2) { +- cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; +- defaultLine = line; +- } +- +- /* If we find a generic config option which should live at the +- top of the file, move it there. Old versions of grubby were +- probably responsible for putting new images in the wrong +- place in front of it anyway. */ +- if (sawEntry && line->type == LT_GENERIC) { +- struct singleLine **l = &cfg->theLines; +- struct singleLine **last_nonws = &cfg->theLines; +- while (*l) { +- if ((*l)->type != LT_WHITESPACE) +- last_nonws = &((*l)->next); +- l = &((*l)->next); ++ if (line->type == LT_DEFAULT && line->numElements == 2) { ++ cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; ++ defaultLine = line; + } +- line->next = *last_nonws; +- *last_nonws = line; +- movedLine = 1; +- continue; /* without setting 'last' */ +- } + +- /* If a second line of whitespace happens after a generic option +- which was moved, drop it. */ +- if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) { +- lineFree(line); +- free(line); ++ /* If we find a generic config option which should live at the ++ top of the file, move it there. Old versions of grubby were ++ probably responsible for putting new images in the wrong ++ place in front of it anyway. */ ++ if (sawEntry && line->type == LT_GENERIC) { ++ struct singleLine **l = &cfg->theLines; ++ struct singleLine **last_nonws = &cfg->theLines; ++ while (*l) { ++ if ((*l)->type != LT_WHITESPACE) ++ last_nonws = &((*l)->next); ++ l = &((*l)->next); ++ } ++ line->next = *last_nonws; ++ *last_nonws = line; ++ movedLine = 1; ++ continue; /* without setting 'last' */ ++ } ++ ++ /* If a second line of whitespace happens after a generic option ++ which was moved, drop it. */ ++ if (movedLine && line->type == LT_WHITESPACE ++ && last->type == LT_WHITESPACE) { ++ lineFree(line); ++ free(line); ++ movedLine = 0; ++ continue; ++ } + movedLine = 0; +- continue; +- } +- movedLine = 0; + +- if (sawEntry) { +- if (!entry->lines) +- entry->lines = line; +- else +- last->next = line; +- dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry); ++ if (sawEntry) { ++ if (!entry->lines) ++ entry->lines = line; ++ else ++ last->next = line; ++ dbgPrintf("readConfig added %s to %p\n", ++ getKeyByType(line->type, cfi), entry); ++ ++ /* we could have seen this outside of an entry... if so, we ++ * ignore it like any other line we don't grok */ ++ if (line->type == LT_ENTRY_END && sawEntry) ++ sawEntry = 0; ++ } else { ++ if (!cfg->theLines) ++ cfg->theLines = line; ++ else ++ last->next = line; ++ dbgPrintf("readConfig added %s to cfg\n", ++ getKeyByType(line->type, cfi)); ++ } + +- /* we could have seen this outside of an entry... if so, we +- * ignore it like any other line we don't grok */ +- if (line->type == LT_ENTRY_END && sawEntry) +- sawEntry = 0; +- } else { +- if (!cfg->theLines) +- cfg->theLines = line; +- else +- last->next = line; +- dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi)); ++ last = line; + } + +- last = line; +- } +- +- free(incoming); ++ free(incoming); ++ ++ dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset"); ++ if (defaultLine) { ++ if (defaultLine->numElements > 2 && ++ cfi->defaultSupportSaved && ++ !strncmp(defaultLine->elements[2].item, ++ "\"${saved_entry}\"", 16)) { ++ cfg->cfi->defaultIsSaved = 1; ++ cfg->defaultImage = DEFAULT_SAVED_GRUB2; ++ if (cfg->cfi->getEnv) { ++ char *defTitle = ++ cfi->getEnv(cfg->cfi, "saved_entry"); ++ if (defTitle) { ++ int index = 0; ++ if (isnumber(defTitle)) { ++ index = atoi(defTitle); ++ entry = ++ findEntryByIndex(cfg, ++ index); ++ } else { ++ entry = ++ findEntryByTitle(cfg, ++ defTitle, ++ &index); ++ } ++ if (entry) ++ cfg->defaultImage = index; ++ } ++ } ++ } else if (cfi->defaultIsVariable) { ++ char *value = defaultLine->elements[2].item; ++ while (*value && (*value == '"' || *value == '\'' || ++ *value == ' ' || *value == '\t')) ++ value++; ++ cfg->defaultImage = strtol(value, &end, 10); ++ while (*end && (*end == '"' || *end == '\'' || ++ *end == ' ' || *end == '\t')) ++ end++; ++ if (*end) ++ cfg->defaultImage = -1; ++ } else if (cfi->defaultSupportSaved && ++ !strncmp(defaultLine->elements[1].item, "saved", ++ 5)) { ++ cfg->defaultImage = DEFAULT_SAVED; ++ } else if (cfi->defaultIsIndex) { ++ cfg->defaultImage = ++ strtol(defaultLine->elements[1].item, &end, 10); ++ if (*end) ++ cfg->defaultImage = -1; ++ } else if (defaultLine->numElements >= 2) { ++ int i = 0; ++ while ((entry = findEntryByIndex(cfg, i))) { ++ for (line = entry->lines; line; ++ line = line->next) ++ if (line->type == LT_TITLE) ++ break; ++ ++ if (!cfi->titleBracketed) { ++ if (line && (line->numElements >= 2) && ++ !strcmp(defaultLine->elements[1]. ++ item, ++ line->elements[1].item)) ++ break; ++ } else if (line) { ++ if (!strcmp ++ (defaultLine->elements[1].item, ++ extractTitle(cfg, line))) ++ break; ++ } ++ i++; ++ entry = NULL; ++ } + +- dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset"); +- if (defaultLine) { +- if (defaultLine->numElements > 2 && +- cfi->defaultSupportSaved && +- !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) { +- cfg->cfi->defaultIsSaved = 1; +- cfg->defaultImage = DEFAULT_SAVED_GRUB2; +- if (cfg->cfi->getEnv) { +- char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); +- if (defTitle) { ++ if (entry) { ++ cfg->defaultImage = i; ++ } else { ++ cfg->defaultImage = -1; ++ } ++ } ++ } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) { ++ char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); ++ if (defTitle) { + int index = 0; + if (isnumber(defTitle)) { +- index = atoi(defTitle); +- entry = findEntryByIndex(cfg, index); ++ index = atoi(defTitle); ++ entry = findEntryByIndex(cfg, index); + } else { +- entry = findEntryByTitle(cfg, defTitle, &index); ++ entry = findEntryByTitle(cfg, defTitle, &index); + } + if (entry) +- cfg->defaultImage = index; +- } ++ cfg->defaultImage = index; + } +- } else if (cfi->defaultIsVariable) { +- char *value = defaultLine->elements[2].item; +- while (*value && (*value == '"' || *value == '\'' || +- *value == ' ' || *value == '\t')) +- value++; +- cfg->defaultImage = strtol(value, &end, 10); +- while (*end && (*end == '"' || *end == '\'' || +- *end == ' ' || *end == '\t')) +- end++; +- if (*end) cfg->defaultImage = -1; +- } else if (cfi->defaultSupportSaved && +- !strncmp(defaultLine->elements[1].item, "saved", 5)) { +- cfg->defaultImage = DEFAULT_SAVED; +- } else if (cfi->defaultIsIndex) { +- cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10); +- if (*end) cfg->defaultImage = -1; +- } else if (defaultLine->numElements >= 2) { +- int i = 0; +- while ((entry = findEntryByIndex(cfg, i))) { +- for (line = entry->lines; line; line = line->next) +- if (line->type == LT_TITLE) break; +- +- if (!cfi->titleBracketed) { +- if (line && (line->numElements >= 2) && +- !strcmp(defaultLine->elements[1].item, +- line->elements[1].item)) break; +- } else if (line) { +- if (!strcmp(defaultLine->elements[1].item, +- extractTitle(cfg, line))) break; +- } +- i++; +- entry = NULL; +- } +- +- if (entry){ +- cfg->defaultImage = i; +- }else{ +- cfg->defaultImage = -1; +- } +- } +- } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) { +- char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); +- if (defTitle) { +- int index = 0; +- if (isnumber(defTitle)) { +- index = atoi(defTitle); +- entry = findEntryByIndex(cfg, index); +- } else { +- entry = findEntryByTitle(cfg, defTitle, &index); +- } +- if (entry) +- cfg->defaultImage = index; +- } +- } else { +- cfg->defaultImage = 0; +- } +- +- return cfg; ++ } else { ++ cfg->defaultImage = 0; ++ } ++ ++ return cfg; + } + +-static void writeDefault(FILE * out, char * indent, +- char * separator, struct grubConfig * cfg) { +- struct singleEntry * entry; +- struct singleLine * line; +- int i; +- +- if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) +- return; +- +- if (cfg->defaultImage == DEFAULT_SAVED) +- fprintf(out, "%sdefault%ssaved\n", indent, separator); +- else if (cfg->cfi->defaultIsSaved) { +- fprintf(out, "%sset default=\"${saved_entry}\"\n", indent); +- if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) { +- char *title; +- entry = findEntryByIndex(cfg, cfg->defaultImage); +- line = getLineByType(LT_MENUENTRY, entry->lines); +- if (!line) +- line = getLineByType(LT_TITLE, entry->lines); +- if (line) { +- title = extractTitle(cfg, line); +- if (title) +- cfg->cfi->setEnv(cfg->cfi, "saved_entry", title); +- } +- } +- } else if (cfg->defaultImage > -1) { +- if (cfg->cfi->defaultIsIndex) { +- if (cfg->cfi->defaultIsVariable) { +- fprintf(out, "%sset default=\"%d\"\n", indent, +- cfg->defaultImage); +- } else { +- fprintf(out, "%sdefault%s%d\n", indent, separator, +- cfg->defaultImage); +- } +- } else { +- int image = cfg->defaultImage; ++static void writeDefault(FILE * out, char *indent, ++ char *separator, struct grubConfig *cfg) ++{ ++ struct singleEntry *entry; ++ struct singleLine *line; ++ int i; + +- entry = cfg->entries; +- while (entry && entry->skip) +- entry = entry->next; ++ if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) ++ return; + +- i = 0; +- while (entry && i < image) { +- entry = entry->next; ++ if (cfg->defaultImage == DEFAULT_SAVED) ++ fprintf(out, "%sdefault%ssaved\n", indent, separator); ++ else if (cfg->cfi->defaultIsSaved) { ++ fprintf(out, "%sset default=\"${saved_entry}\"\n", indent); ++ if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) { ++ char *title; ++ entry = findEntryByIndex(cfg, cfg->defaultImage); ++ line = getLineByType(LT_MENUENTRY, entry->lines); ++ if (!line) ++ line = getLineByType(LT_TITLE, entry->lines); ++ if (line) { ++ title = extractTitle(cfg, line); ++ if (title) ++ cfg->cfi->setEnv(cfg->cfi, ++ "saved_entry", title); ++ } ++ } ++ } else if (cfg->defaultImage > -1) { ++ if (cfg->cfi->defaultIsIndex) { ++ if (cfg->cfi->defaultIsVariable) { ++ fprintf(out, "%sset default=\"%d\"\n", indent, ++ cfg->defaultImage); ++ } else { ++ fprintf(out, "%sdefault%s%d\n", indent, ++ separator, cfg->defaultImage); ++ } ++ } else { ++ int image = cfg->defaultImage; + +- while (entry && entry->skip) +- entry = entry->next; +- i++; +- } ++ entry = cfg->entries; ++ while (entry && entry->skip) ++ entry = entry->next; + +- if (!entry) +- return; ++ i = 0; ++ while (entry && i < image) { ++ entry = entry->next; + +- line = getLineByType(LT_TITLE, entry->lines); ++ while (entry && entry->skip) ++ entry = entry->next; ++ i++; ++ } + +- if (line && line->numElements >= 2) +- fprintf(out, "%sdefault%s%s\n", indent, separator, +- line->elements[1].item); +- else if (line && (line->numElements == 1) && +- cfg->cfi->titleBracketed) { +- char *title = extractTitle(cfg, line); +- if (title) { +- fprintf(out, "%sdefault%s%s\n", indent, separator, title); +- free(title); ++ if (!entry) ++ return; ++ ++ line = getLineByType(LT_TITLE, entry->lines); ++ ++ if (line && line->numElements >= 2) ++ fprintf(out, "%sdefault%s%s\n", indent, ++ separator, line->elements[1].item); ++ else if (line && (line->numElements == 1) ++ && cfg->cfi->titleBracketed) { ++ char *title = extractTitle(cfg, line); ++ if (title) { ++ fprintf(out, "%sdefault%s%s\n", indent, ++ separator, title); ++ free(title); ++ } ++ } + } +- } + } +- } + } + +-static int writeConfig(struct grubConfig * cfg, char * outName, +- const char * prefix) { +- FILE * out; +- struct singleLine * line; +- struct singleEntry * entry; +- char * tmpOutName; +- int needs = MAIN_DEFAULT; +- struct stat sb; +- int i; +- +- if (!strcmp(outName, "-")) { +- out = stdout; +- tmpOutName = NULL; +- } else { +- if (!lstat(outName, &sb) && S_ISLNK(sb.st_mode)) { +- char * buf; +- int len = 256; +- int rc; +- +- /* most likely the symlink is relative, so change our +- directory to the dir of the symlink */ +- char *dir = strdupa(outName); +- rc = chdir(dirname(dir)); +- do { +- buf = alloca(len + 1); +- rc = readlink(basename(outName), buf, len); +- if (rc == len) len += 256; +- } while (rc == len); +- +- if (rc < 0) { +- fprintf(stderr, _("grubby: error readlink link %s: %s\n"), +- outName, strerror(errno)); +- return 1; +- } +- +- outName = buf; +- outName[rc] = '\0'; +- } +- +- tmpOutName = alloca(strlen(outName) + 2); +- sprintf(tmpOutName, "%s-", outName); +- out = fopen(tmpOutName, "w"); +- if (!out) { +- fprintf(stderr, _("grubby: error creating %s: %s\n"), tmpOutName, +- strerror(errno)); +- return 1; +- } +- +- if (!stat(outName, &sb)) { +- if (chmod(tmpOutName, sb.st_mode & ~(S_IFMT))) { +- fprintf(stderr, _("grubby: error setting perms on %s: %s\n"), +- tmpOutName, strerror(errno)); +- fclose(out); +- unlink(tmpOutName); +- return 1; +- } +- } +- } +- +- line = cfg->theLines; +- struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi); +- while (line) { +- if (line->type == LT_SET_VARIABLE && defaultKw && +- line->numElements == 3 && +- !strcmp(line->elements[1].item, defaultKw->key) && +- !is_special_grub2_variable(line->elements[2].item)) { +- writeDefault(out, line->indent, line->elements[0].indent, cfg); +- needs &= ~MAIN_DEFAULT; +- } else if (line->type == LT_DEFAULT) { +- writeDefault(out, line->indent, line->elements[0].indent, cfg); +- needs &= ~MAIN_DEFAULT; +- } else if (line->type == LT_FALLBACK) { +- if (cfg->fallbackImage > -1) +- fprintf(out, "%s%s%s%d\n", line->indent, +- line->elements[0].item, line->elements[0].indent, +- cfg->fallbackImage); ++static int writeConfig(struct grubConfig *cfg, char *outName, ++ const char *prefix) ++{ ++ FILE *out; ++ struct singleLine *line; ++ struct singleEntry *entry; ++ char *tmpOutName; ++ int needs = MAIN_DEFAULT; ++ struct stat sb; ++ int i; ++ ++ if (!strcmp(outName, "-")) { ++ out = stdout; ++ tmpOutName = NULL; + } else { +- if (lineWrite(out, line, cfg->cfi) == -1) { +- fprintf(stderr, _("grubby: error writing %s: %s\n"), +- tmpOutName, strerror(errno)); +- fclose(out); +- unlink(tmpOutName); +- return 1; +- } +- } ++ if (!lstat(outName, &sb) && S_ISLNK(sb.st_mode)) { ++ char *buf; ++ int len = 256; ++ int rc; ++ ++ /* most likely the symlink is relative, so change our ++ directory to the dir of the symlink */ ++ char *dir = strdupa(outName); ++ rc = chdir(dirname(dir)); ++ do { ++ buf = alloca(len + 1); ++ rc = readlink(basename(outName), buf, len); ++ if (rc == len) ++ len += 256; ++ } while (rc == len); ++ ++ if (rc < 0) { ++ fprintf(stderr, ++ _ ++ ("grubby: error readlink link %s: %s\n"), ++ outName, strerror(errno)); ++ return 1; ++ } + +- line = line->next; +- } ++ outName = buf; ++ outName[rc] = '\0'; ++ } + +- if (needs & MAIN_DEFAULT) { +- writeDefault(out, cfg->primaryIndent, "=", cfg); +- needs &= ~MAIN_DEFAULT; +- } ++ tmpOutName = alloca(strlen(outName) + 2); ++ sprintf(tmpOutName, "%s-", outName); ++ out = fopen(tmpOutName, "w"); ++ if (!out) { ++ fprintf(stderr, _("grubby: error creating %s: %s\n"), ++ tmpOutName, strerror(errno)); ++ return 1; ++ } + +- i = 0; +- while ((entry = findEntryByIndex(cfg, i++))) { +- if (entry->skip) continue; ++ if (!stat(outName, &sb)) { ++ if (chmod(tmpOutName, sb.st_mode & ~(S_IFMT))) { ++ fprintf(stderr, ++ _ ++ ("grubby: error setting perms on %s: %s\n"), ++ tmpOutName, strerror(errno)); ++ fclose(out); ++ unlink(tmpOutName); ++ return 1; ++ } ++ } ++ } + +- line = entry->lines; ++ line = cfg->theLines; ++ struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi); + while (line) { +- if (lineWrite(out, line, cfg->cfi) == -1) { +- fprintf(stderr, _("grubby: error writing %s: %s\n"), +- tmpOutName, strerror(errno)); +- fclose(out); +- unlink(tmpOutName); +- return 1; +- } +- line = line->next; +- } +- } +- +- if (tmpOutName) { +- if (rename(tmpOutName, outName)) { +- fprintf(stderr, _("grubby: error moving %s to %s: %s\n"), +- tmpOutName, outName, strerror(errno)); +- unlink(outName); +- return 1; +- } +- } +- +- return 0; +-} +- +-static int numEntries(struct grubConfig *cfg) { +- int i = 0; +- struct singleEntry * entry; +- +- entry = cfg->entries; +- while (entry) { +- if (!entry->skip) +- i++; +- entry = entry->next; +- } +- return i; +-} ++ if (line->type == LT_SET_VARIABLE && defaultKw && ++ line->numElements == 3 && ++ !strcmp(line->elements[1].item, defaultKw->key) && ++ !is_special_grub2_variable(line->elements[2].item)) { ++ writeDefault(out, line->indent, ++ line->elements[0].indent, cfg); ++ needs &= ~MAIN_DEFAULT; ++ } else if (line->type == LT_DEFAULT) { ++ writeDefault(out, line->indent, ++ line->elements[0].indent, cfg); ++ needs &= ~MAIN_DEFAULT; ++ } else if (line->type == LT_FALLBACK) { ++ if (cfg->fallbackImage > -1) ++ fprintf(out, "%s%s%s%d\n", line->indent, ++ line->elements[0].item, ++ line->elements[0].indent, ++ cfg->fallbackImage); ++ } else { ++ if (lineWrite(out, line, cfg->cfi) == -1) { ++ fprintf(stderr, ++ _("grubby: error writing %s: %s\n"), ++ tmpOutName, strerror(errno)); ++ fclose(out); ++ unlink(tmpOutName); ++ return 1; ++ } ++ } + +-static char *findDiskForRoot() +-{ +- int fd; +- char buf[65536]; +- char *devname; +- char *chptr; +- int rc; +- +- if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) { +- fprintf(stderr, "grubby: failed to open %s: %s\n", +- _PATH_MOUNTED, strerror(errno)); +- return NULL; +- } +- +- rc = read(fd, buf, sizeof(buf) - 1); +- if (rc <= 0) { +- fprintf(stderr, "grubby: failed to read %s: %s\n", +- _PATH_MOUNTED, strerror(errno)); +- close(fd); +- return NULL; +- } +- close(fd); +- buf[rc] = '\0'; +- chptr = buf; +- +- char *foundanswer = NULL; +- +- while (chptr && chptr != buf+rc) { +- devname = chptr; +- +- /* +- * The first column of a mtab entry is the device, but if the entry is a +- * special device it won't start with /, so move on to the next line. +- */ +- if (*devname != '/') { +- chptr = strchr(chptr, '\n'); +- if (chptr) +- chptr++; +- continue; +- } +- +- /* Seek to the next space */ +- chptr = strchr(chptr, ' '); +- if (!chptr) { +- fprintf(stderr, "grubby: error parsing %s: %s\n", +- _PATH_MOUNTED, strerror(errno)); +- return NULL; +- } +- +- /* +- * The second column of a mtab entry is the mount point, we are looking +- * for '/' obviously. +- */ +- if (*(++chptr) == '/' && *(++chptr) == ' ') { +- /* remember the last / entry in mtab */ +- foundanswer = devname; +- } +- +- /* Next line */ +- chptr = strchr(chptr, '\n'); +- if (chptr) +- chptr++; +- } +- +- /* Return the last / entry found */ +- if (foundanswer) { +- chptr = strchr(foundanswer, ' '); +- *chptr = '\0'; +- return strdup(foundanswer); +- } +- +- return NULL; +-} ++ line = line->next; ++ } + +-void printEntry(struct singleEntry * entry, FILE *f) { +- int i; +- struct singleLine * line; ++ if (needs & MAIN_DEFAULT) { ++ writeDefault(out, cfg->primaryIndent, "=", cfg); ++ needs &= ~MAIN_DEFAULT; ++ } + +- for (line = entry->lines; line; line = line->next) { +- log_message(f, "DBG: %s", line->indent); +- for (i = 0; i < line->numElements; i++) { +- /* Need to handle this, because we strip the quotes from +- * menuentry when read it. */ +- if (line->type == LT_MENUENTRY && i == 1) { +- if(!isquote(*line->elements[i].item)) +- log_message(f, "\'%s\'", line->elements[i].item); +- else +- log_message(f, "%s", line->elements[i].item); +- log_message(f, "%s", line->elements[i].indent); +- +- continue; +- } +- +- log_message(f, "%s%s", +- line->elements[i].item, line->elements[i].indent); +- } +- log_message(f, "\n"); +- } ++ i = 0; ++ while ((entry = findEntryByIndex(cfg, i++))) { ++ if (entry->skip) ++ continue; ++ ++ line = entry->lines; ++ while (line) { ++ if (lineWrite(out, line, cfg->cfi) == -1) { ++ fprintf(stderr, ++ _("grubby: error writing %s: %s\n"), ++ tmpOutName, strerror(errno)); ++ fclose(out); ++ unlink(tmpOutName); ++ return 1; ++ } ++ line = line->next; ++ } ++ } ++ ++ if (tmpOutName) { ++ if (rename(tmpOutName, outName)) { ++ fprintf(stderr, ++ _("grubby: error moving %s to %s: %s\n"), ++ tmpOutName, outName, strerror(errno)); ++ unlink(outName); ++ return 1; ++ } ++ } ++ ++ return 0; + } + +-void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...) ++static int numEntries(struct grubConfig *cfg) + { +- static int once; +- va_list argp, argq; +- +- va_start(argp, fmt); +- +- va_copy(argq, argp); +- if (!once) { +- log_time(NULL); +- log_message(NULL, "command line: %s\n", saved_command_line); +- } +- log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed"); +- log_vmessage(NULL, fmt, argq); +- +- printEntry(entry, NULL); +- va_end(argq); +- +- if (!debug) { +- once = 1; +- va_end(argp); +- return; +- } ++ int i = 0; ++ struct singleEntry *entry; ++ ++ entry = cfg->entries; ++ while (entry) { ++ if (!entry->skip) ++ i++; ++ entry = entry->next; ++ } ++ return i; ++} ++ ++static char *findDiskForRoot() ++{ ++ int fd; ++ char buf[65536]; ++ char *devname; ++ char *chptr; ++ int rc; ++ ++ if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) { ++ fprintf(stderr, "grubby: failed to open %s: %s\n", ++ _PATH_MOUNTED, strerror(errno)); ++ return NULL; ++ } ++ ++ rc = read(fd, buf, sizeof(buf) - 1); ++ if (rc <= 0) { ++ fprintf(stderr, "grubby: failed to read %s: %s\n", ++ _PATH_MOUNTED, strerror(errno)); ++ close(fd); ++ return NULL; ++ } ++ close(fd); ++ buf[rc] = '\0'; ++ chptr = buf; ++ ++ char *foundanswer = NULL; ++ ++ while (chptr && chptr != buf + rc) { ++ devname = chptr; ++ ++ /* ++ * The first column of a mtab entry is the device, but if the entry is a ++ * special device it won't start with /, so move on to the next line. ++ */ ++ if (*devname != '/') { ++ chptr = strchr(chptr, '\n'); ++ if (chptr) ++ chptr++; ++ continue; ++ } ++ ++ /* Seek to the next space */ ++ chptr = strchr(chptr, ' '); ++ if (!chptr) { ++ fprintf(stderr, "grubby: error parsing %s: %s\n", ++ _PATH_MOUNTED, strerror(errno)); ++ return NULL; ++ } ++ ++ /* ++ * The second column of a mtab entry is the mount point, we are looking ++ * for '/' obviously. ++ */ ++ if (*(++chptr) == '/' && *(++chptr) == ' ') { ++ /* remember the last / entry in mtab */ ++ foundanswer = devname; ++ } ++ ++ /* Next line */ ++ chptr = strchr(chptr, '\n'); ++ if (chptr) ++ chptr++; ++ } ++ ++ /* Return the last / entry found */ ++ if (foundanswer) { ++ chptr = strchr(foundanswer, ' '); ++ *chptr = '\0'; ++ return strdup(foundanswer); ++ } ++ ++ return NULL; ++} ++ ++void printEntry(struct singleEntry *entry, FILE * f) ++{ ++ int i; ++ struct singleLine *line; ++ ++ for (line = entry->lines; line; line = line->next) { ++ log_message(f, "DBG: %s", line->indent); ++ for (i = 0; i < line->numElements; i++) { ++ /* Need to handle this, because we strip the quotes from ++ * menuentry when read it. */ ++ if (line->type == LT_MENUENTRY && i == 1) { ++ if (!isquote(*line->elements[i].item)) ++ log_message(f, "\'%s\'", ++ line->elements[i].item); ++ else ++ log_message(f, "%s", ++ line->elements[i].item); ++ log_message(f, "%s", line->elements[i].indent); ++ ++ continue; ++ } ++ ++ log_message(f, "%s%s", ++ line->elements[i].item, ++ line->elements[i].indent); ++ } ++ log_message(f, "\n"); ++ } ++} + +- if (okay) { ++void notSuitablePrintf(struct singleEntry *entry, int okay, const char *fmt, ++ ...) ++{ ++ static int once; ++ va_list argp, argq; ++ ++ va_start(argp, fmt); ++ ++ va_copy(argq, argp); ++ if (!once) { ++ log_time(NULL); ++ log_message(NULL, "command line: %s\n", saved_command_line); ++ } ++ log_message(NULL, "DBG: Image entry %s: ", ++ okay ? "succeeded" : "failed"); ++ log_vmessage(NULL, fmt, argq); ++ ++ printEntry(entry, NULL); ++ va_end(argq); ++ ++ if (!debug) { ++ once = 1; ++ va_end(argp); ++ return; ++ } ++ ++ if (okay) { ++ va_end(argp); ++ return; ++ } ++ ++ if (!once) ++ log_message(stderr, "DBG: command line: %s\n", ++ saved_command_line); ++ once = 1; ++ fprintf(stderr, "DBG: Image entry failed: "); ++ vfprintf(stderr, fmt, argp); ++ printEntry(entry, stderr); + va_end(argp); +- return; +- } +- +- if (!once) +- log_message(stderr, "DBG: command line: %s\n", saved_command_line); +- once = 1; +- fprintf(stderr, "DBG: Image entry failed: "); +- vfprintf(stderr, fmt, argp); +- printEntry(entry, stderr); +- va_end(argp); + } + + #define beginswith(s, c) ((s) && (s)[0] == (c)) +@@ -1860,281 +1979,317 @@ static int endswith(const char *s, char c) + return s[slen] == c; + } + +-int suitableImage(struct singleEntry * entry, const char * bootPrefix, +- int skipRemoved, int flags) { +- struct singleLine * line; +- char * fullName; +- int i; +- char * dev; +- char * rootspec; +- char * rootdev; +- +- if (skipRemoved && entry->skip) { +- notSuitablePrintf(entry, 0, "marked to skip\n"); +- return 0; +- } ++int suitableImage(struct singleEntry *entry, const char *bootPrefix, ++ int skipRemoved, int flags) ++{ ++ struct singleLine *line; ++ char *fullName; ++ int i; ++ char *dev; ++ char *rootspec; ++ char *rootdev; ++ ++ if (skipRemoved && entry->skip) { ++ notSuitablePrintf(entry, 0, "marked to skip\n"); ++ return 0; ++ } + +- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); +- if (!line) { +- notSuitablePrintf(entry, 0, "no line found\n"); +- return 0; +- } +- if (line->numElements < 2) { +- notSuitablePrintf(entry, 0, "line has only %d elements\n", +- line->numElements); +- return 0; +- } +- +- if (flags & GRUBBY_BADIMAGE_OKAY) { +- notSuitablePrintf(entry, 1, "\n"); +- return 1; +- } +- +- fullName = alloca(strlen(bootPrefix) + +- strlen(line->elements[1].item) + 1); +- rootspec = getRootSpecifier(line->elements[1].item); +- int rootspec_offset = rootspec ? strlen(rootspec) : 0; +- int hasslash = endswith(bootPrefix, '/') || +- beginswith(line->elements[1].item + rootspec_offset, '/'); +- sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/", +- line->elements[1].item + rootspec_offset); +- if (access(fullName, R_OK)) { +- notSuitablePrintf(entry, 0, "access to %s failed\n", fullName); +- return 0; +- } +- for (i = 2; i < line->numElements; i++) +- if (!strncasecmp(line->elements[i].item, "root=", 5)) break; +- if (i < line->numElements) { +- dev = line->elements[i].item + 5; +- } else { +- /* look for a lilo style LT_ROOT line */ +- line = getLineByType(LT_ROOT, entry->lines); ++ line = ++ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | LT_KERNEL_16, ++ entry->lines); ++ if (!line) { ++ notSuitablePrintf(entry, 0, "no line found\n"); ++ return 0; ++ } ++ if (line->numElements < 2) { ++ notSuitablePrintf(entry, 0, "line has only %d elements\n", ++ line->numElements); ++ return 0; ++ } + +- if (line && line->numElements >= 2) { +- dev = line->elements[1].item; +- } else { +- /* 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. +- */ +- line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines); ++ if (flags & GRUBBY_BADIMAGE_OKAY) { ++ notSuitablePrintf(entry, 1, "\n"); ++ return 1; ++ } + +- /* failed to find one */ +- if (!line) { +- notSuitablePrintf(entry, 0, "no line found\n"); ++ fullName = alloca(strlen(bootPrefix) + ++ strlen(line->elements[1].item) + 1); ++ rootspec = getRootSpecifier(line->elements[1].item); ++ int rootspec_offset = rootspec ? strlen(rootspec) : 0; ++ int hasslash = endswith(bootPrefix, '/') || ++ beginswith(line->elements[1].item + rootspec_offset, '/'); ++ sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/", ++ line->elements[1].item + rootspec_offset); ++ if (access(fullName, R_OK)) { ++ notSuitablePrintf(entry, 0, "access to %s failed\n", fullName); + return 0; +- } +- +- for (i = 1; i < line->numElements; i++) +- if (!strncasecmp(line->elements[i].item, "root=", 5)) break; +- if (i < line->numElements) +- dev = line->elements[i].item + 5; +- else { +- notSuitablePrintf(entry, 0, "no root= entry found\n"); +- /* it failed too... can't find root= */ +- return 0; +- } +- } +- } +- +- dev = getpathbyspec(dev); +- if (!getpathbyspec(dev)) { +- notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev); +- return 0; +- } else ++ } ++ for (i = 2; i < line->numElements; i++) ++ if (!strncasecmp(line->elements[i].item, "root=", 5)) ++ break; ++ if (i < line->numElements) { ++ dev = line->elements[i].item + 5; ++ } else { ++ /* look for a lilo style LT_ROOT line */ ++ line = getLineByType(LT_ROOT, entry->lines); ++ ++ if (line && line->numElements >= 2) { ++ dev = line->elements[1].item; ++ } else { ++ /* 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. ++ */ ++ line = ++ getLineByType(LT_KERNELARGS | LT_MBMODULE, ++ entry->lines); ++ ++ /* failed to find one */ ++ if (!line) { ++ notSuitablePrintf(entry, 0, "no line found\n"); ++ return 0; ++ } ++ ++ for (i = 1; i < line->numElements; i++) ++ if (!strncasecmp ++ (line->elements[i].item, "root=", 5)) ++ break; ++ if (i < line->numElements) ++ dev = line->elements[i].item + 5; ++ else { ++ notSuitablePrintf(entry, 0, ++ "no root= entry found\n"); ++ /* it failed too... can't find root= */ ++ return 0; ++ } ++ } ++ } ++ + dev = getpathbyspec(dev); ++ if (!getpathbyspec(dev)) { ++ notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", ++ dev); ++ return 0; ++ } else ++ dev = getpathbyspec(dev); + +- rootdev = findDiskForRoot(); +- if (!rootdev) { +- notSuitablePrintf(entry, 0, "can't find root device\n"); +- return 0; +- } +- +- if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) { +- notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n", +- getuuidbydev(rootdev), getuuidbydev(dev)); +- free(rootdev); +- return 0; +- } +- +- if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { +- notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n", +- getuuidbydev(rootdev), getuuidbydev(dev)); +- free(rootdev); +- return 0; +- } ++ rootdev = findDiskForRoot(); ++ if (!rootdev) { ++ notSuitablePrintf(entry, 0, "can't find root device\n"); ++ return 0; ++ } + +- free(rootdev); +- notSuitablePrintf(entry, 1, "\n"); ++ if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) { ++ notSuitablePrintf(entry, 0, ++ "uuid missing: rootdev %s, dev %s\n", ++ getuuidbydev(rootdev), getuuidbydev(dev)); ++ free(rootdev); ++ return 0; ++ } ++ ++ if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { ++ notSuitablePrintf(entry, 0, ++ "uuid mismatch: rootdev %s, dev %s\n", ++ getuuidbydev(rootdev), getuuidbydev(dev)); ++ free(rootdev); ++ return 0; ++ } ++ ++ free(rootdev); ++ notSuitablePrintf(entry, 1, "\n"); + +- return 1; ++ return 1; + } + + /* returns the first match on or after the one pointed to by index (if index + is not NULL) which is not marked as skip */ +-struct singleEntry * findEntryByPath(struct grubConfig * config, +- const char * kernel, const char * prefix, +- int * index) { +- struct singleEntry * entry = NULL; +- struct singleLine * line; +- int i; +- char * chptr; +- char * rootspec = NULL; +- enum lineType_e checkType = LT_KERNEL; +- +- if (isdigit(*kernel)) { +- int * indexVars = alloca(sizeof(*indexVars) * strlen(kernel)); +- +- i = 0; +- indexVars[i] = strtol(kernel, &chptr, 10); +- while (*chptr == ',') { +- i++; +- kernel = chptr + 1; +- indexVars[i] = strtol(kernel, &chptr, 10); +- } ++struct singleEntry *findEntryByPath(struct grubConfig *config, ++ const char *kernel, const char *prefix, ++ int *index) ++{ ++ struct singleEntry *entry = NULL; ++ struct singleLine *line; ++ int i; ++ char *chptr; ++ char *rootspec = NULL; ++ enum lineType_e checkType = LT_KERNEL; ++ ++ if (isdigit(*kernel)) { ++ int *indexVars = alloca(sizeof(*indexVars) * strlen(kernel)); ++ ++ i = 0; ++ indexVars[i] = strtol(kernel, &chptr, 10); ++ while (*chptr == ',') { ++ i++; ++ kernel = chptr + 1; ++ indexVars[i] = strtol(kernel, &chptr, 10); ++ } + +- if (*chptr) { +- /* can't parse it, bail */ +- return NULL; +- } ++ if (*chptr) { ++ /* can't parse it, bail */ ++ return NULL; ++ } + +- indexVars[i + 1] = -1; ++ indexVars[i + 1] = -1; + +- i = 0; +- if (index) { +- while (i < *index) { +- i++; +- if (indexVars[i] == -1) return NULL; +- } +- } ++ i = 0; ++ if (index) { ++ while (i < *index) { ++ i++; ++ if (indexVars[i] == -1) ++ return NULL; ++ } ++ } + +- entry = findEntryByIndex(config, indexVars[i]); +- if (!entry) return NULL; ++ entry = findEntryByIndex(config, indexVars[i]); ++ if (!entry) ++ return NULL; + +- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); +- if (!line) return NULL; ++ line = ++ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | ++ LT_KERNEL_16, entry->lines); ++ if (!line) ++ return NULL; + +- if (index) *index = indexVars[i]; +- return entry; +- } +- +- if (!strcmp(kernel, "DEFAULT")) { +- if (index && *index > config->defaultImage) { +- entry = NULL; +- } else { +- entry = findEntryByIndex(config, config->defaultImage); +- if (entry && entry->skip) +- entry = NULL; +- else if (index) +- *index = config->defaultImage; ++ if (index) ++ *index = indexVars[i]; ++ return entry; + } +- } else if (!strcmp(kernel, "ALL")) { +- if (index) +- i = *index; +- else +- i = 0; + +- while ((entry = findEntryByIndex(config, i))) { +- if (!entry->skip) break; +- i++; +- } ++ if (!strcmp(kernel, "DEFAULT")) { ++ if (index && *index > config->defaultImage) { ++ entry = NULL; ++ } else { ++ entry = findEntryByIndex(config, config->defaultImage); ++ if (entry && entry->skip) ++ entry = NULL; ++ else if (index) ++ *index = config->defaultImage; ++ } ++ } else if (!strcmp(kernel, "ALL")) { ++ if (index) ++ i = *index; ++ else ++ i = 0; + +- if (entry && index) +- *index = i; +- } else { +- if (index) +- i = *index; +- else +- i = 0; ++ while ((entry = findEntryByIndex(config, i))) { ++ if (!entry->skip) ++ break; ++ i++; ++ } + +- if (!strncmp(kernel, "TITLE=", 6)) { +- prefix = ""; +- checkType = LT_TITLE|LT_MENUENTRY; +- kernel += 6; +- } ++ if (entry && index) ++ *index = i; ++ } else { ++ if (index) ++ i = *index; ++ else ++ i = 0; + +- for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) { +- if (entry->skip) continue; ++ if (!strncmp(kernel, "TITLE=", 6)) { ++ prefix = ""; ++ checkType = LT_TITLE | LT_MENUENTRY; ++ kernel += 6; ++ } + +- dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry); ++ for (entry = findEntryByIndex(config, i); entry; ++ entry = entry->next, i++) { ++ if (entry->skip) ++ continue; ++ ++ dbgPrintf("findEntryByPath looking for %d %s in %p\n", ++ checkType, kernel, entry); ++ ++ /* check all the lines matching checkType */ ++ for (line = entry->lines; line; line = line->next) { ++ enum lineType_e ct = checkType; ++ if (entry->multiboot && checkType == LT_KERNEL) ++ ct = LT_KERNEL | LT_KERNEL_EFI | ++ LT_MBMODULE | LT_HYPER | ++ LT_KERNEL_16; ++ else if (checkType & LT_KERNEL) ++ ct = checkType | LT_KERNEL_EFI | ++ LT_KERNEL_16; ++ line = getLineByType(ct, line); ++ if (!line) ++ break; /* not found in this entry */ ++ ++ if (line && line->type != LT_MENUENTRY && ++ line->numElements >= 2) { ++ rootspec = ++ getRootSpecifier(line->elements[1]. ++ item); ++ if (!strcmp ++ (line->elements[1].item + ++ ((rootspec != ++ NULL) ? strlen(rootspec) : 0), ++ kernel + strlen(prefix))) ++ break; ++ } ++ if (line->type == LT_MENUENTRY && ++ !strcmp(line->elements[1].item, kernel)) ++ break; ++ } + +- /* check all the lines matching checkType */ +- for (line = entry->lines; line; line = line->next) { +- enum lineType_e ct = checkType; +- if (entry->multiboot && checkType == LT_KERNEL) +- ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16; +- else if (checkType & LT_KERNEL) +- ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16; +- line = getLineByType(ct, line); +- if (!line) +- break; /* not found in this entry */ +- +- if (line && line->type != LT_MENUENTRY && +- line->numElements >= 2) { +- rootspec = getRootSpecifier(line->elements[1].item); +- if (!strcmp(line->elements[1].item + +- ((rootspec != NULL) ? strlen(rootspec) : 0), +- kernel + strlen(prefix))) +- break; ++ /* make sure this entry has a kernel identifier; this skips ++ * non-Linux boot entries (could find netbsd etc, though, which is ++ * unfortunate) ++ */ ++ if (line ++ && getLineByType(LT_KERNEL | LT_HYPER | ++ LT_KERNEL_EFI | LT_KERNEL_16, ++ entry->lines)) ++ break; /* found 'im! */ + } +- if(line->type == LT_MENUENTRY && +- !strcmp(line->elements[1].item, kernel)) +- break; +- } + +- /* make sure this entry has a kernel identifier; this skips +- * non-Linux boot entries (could find netbsd etc, though, which is +- * unfortunate) +- */ +- if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines)) +- break; /* found 'im! */ ++ if (index) ++ *index = i; + } + +- if (index) *index = i; +- } +- +- return entry; ++ return entry; + } + +-struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title, +- int * index) { +- struct singleEntry * entry; +- struct singleLine * line; +- int i; +- char * newtitle; ++struct singleEntry *findEntryByTitle(struct grubConfig *cfg, char *title, ++ int *index) ++{ ++ struct singleEntry *entry; ++ struct singleLine *line; ++ int i; ++ char *newtitle; ++ ++ for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) { ++ if (index && i < *index) ++ continue; ++ line = getLineByType(LT_TITLE, entry->lines); ++ if (!line) ++ line = getLineByType(LT_MENUENTRY, entry->lines); ++ if (!line) ++ continue; ++ newtitle = grub2ExtractTitle(line); ++ if (!newtitle) ++ continue; ++ if (!strcmp(title, newtitle)) ++ break; ++ } + +- for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) { +- if (index && i < *index) +- continue; +- line = getLineByType(LT_TITLE, entry->lines); +- if (!line) +- line = getLineByType(LT_MENUENTRY, entry->lines); +- if (!line) +- continue; +- newtitle = grub2ExtractTitle(line); +- if (!newtitle) +- continue; +- if (!strcmp(title, newtitle)) +- break; +- } +- +- if (!entry) +- return NULL; ++ if (!entry) ++ return NULL; + +- if (index) +- *index = i; +- return entry; ++ if (index) ++ *index = i; ++ return entry; + } + +-struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) { +- struct singleEntry * entry; ++struct singleEntry *findEntryByIndex(struct grubConfig *cfg, int index) ++{ ++ struct singleEntry *entry; + +- entry = cfg->entries; +- while (index && entry) { +- entry = entry->next; +- index--; +- } ++ entry = cfg->entries; ++ while (index && entry) { ++ entry = entry->next; ++ index--; ++ } + +- return entry; ++ return entry; + } + + /* Find a good template to use for the new kernel. An entry is +@@ -2142,2550 +2297,2822 @@ struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) { + * is going to be removed). Try and use the default entry, but + * if that doesn't work just take the first. If we can't find one, + * bail. */ +-struct singleEntry * findTemplate(struct grubConfig * cfg, const char * prefix, +- int * indexPtr, int skipRemoved, int flags) { +- struct singleEntry * entry, * entry2; +- int index; +- +- if (cfg->cfi->defaultIsSaved) { +- if (cfg->cfi->getEnv) { +- char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry"); +- if (defTitle) { +- int index = 0; +- if (isnumber(defTitle)) { +- index = atoi(defTitle); +- entry = findEntryByIndex(cfg, index); +- } else { +- entry = findEntryByTitle(cfg, defTitle, &index); ++struct singleEntry *findTemplate(struct grubConfig *cfg, const char *prefix, ++ int *indexPtr, int skipRemoved, int flags) ++{ ++ struct singleEntry *entry, *entry2; ++ int index; ++ ++ if (cfg->cfi->defaultIsSaved) { ++ if (cfg->cfi->getEnv) { ++ char *defTitle = ++ cfg->cfi->getEnv(cfg->cfi, "saved_entry"); ++ if (defTitle) { ++ int index = 0; ++ if (isnumber(defTitle)) { ++ index = atoi(defTitle); ++ entry = findEntryByIndex(cfg, index); ++ } else { ++ entry = ++ findEntryByTitle(cfg, defTitle, ++ &index); ++ } ++ if (entry ++ && suitableImage(entry, prefix, skipRemoved, ++ flags)) { ++ cfg->defaultImage = index; ++ if (indexPtr) ++ *indexPtr = index; ++ return entry; ++ } ++ } + } ++ } else if (cfg->defaultImage > -1) { ++ entry = findEntryByIndex(cfg, cfg->defaultImage); + if (entry && suitableImage(entry, prefix, skipRemoved, flags)) { +- cfg->defaultImage = index; +- if (indexPtr) +- *indexPtr = index; +- return entry; ++ if (indexPtr) ++ *indexPtr = cfg->defaultImage; ++ return entry; + } +- } + } +- } else if (cfg->defaultImage > -1) { +- entry = findEntryByIndex(cfg, cfg->defaultImage); +- if (entry && suitableImage(entry, prefix, skipRemoved, flags)) { +- if (indexPtr) *indexPtr = cfg->defaultImage; +- return entry; +- } +- } + +- index = 0; +- while ((entry = findEntryByIndex(cfg, index))) { +- if (suitableImage(entry, prefix, skipRemoved, flags)) { +- int j; +- for (j = 0; j < index; j++) { +- entry2 = findEntryByIndex(cfg, j); +- if (entry2->skip) index--; +- } +- if (indexPtr) *indexPtr = index; ++ index = 0; ++ while ((entry = findEntryByIndex(cfg, index))) { ++ if (suitableImage(entry, prefix, skipRemoved, flags)) { ++ int j; ++ for (j = 0; j < index; j++) { ++ entry2 = findEntryByIndex(cfg, j); ++ if (entry2->skip) ++ index--; ++ } ++ if (indexPtr) ++ *indexPtr = index; + +- return entry; +- } ++ return entry; ++ } + +- index++; +- } ++ index++; ++ } + +- fprintf(stderr, _("grubby fatal error: unable to find a suitable template\n")); ++ fprintf(stderr, ++ _("grubby fatal error: unable to find a suitable template\n")); + +- return NULL; ++ return NULL; + } + +-char * findBootPrefix(void) { +- struct stat sb, sb2; ++char *findBootPrefix(void) ++{ ++ struct stat sb, sb2; + +- stat("/", &sb); ++ stat("/", &sb); + #ifdef __ia64__ +- stat("/boot/efi/EFI/redhat/", &sb2); ++ stat("/boot/efi/EFI/redhat/", &sb2); + #else +- stat("/boot", &sb2); ++ stat("/boot", &sb2); + #endif + +- if (sb.st_dev == sb2.st_dev) +- return strdup(""); ++ if (sb.st_dev == sb2.st_dev) ++ return strdup(""); + + #ifdef __ia64__ +- return strdup("/boot/efi/EFI/redhat/"); ++ return strdup("/boot/efi/EFI/redhat/"); + #else +- return strdup("/boot"); ++ return strdup("/boot"); + #endif + } + +-void markRemovedImage(struct grubConfig * cfg, const char * image, +- const char * prefix) { +- struct singleEntry * entry; ++void markRemovedImage(struct grubConfig *cfg, const char *image, ++ const char *prefix) ++{ ++ struct singleEntry *entry; + +- if (!image) +- return; ++ if (!image) ++ return; + +- /* check and see if we're removing the default image */ +- if (isdigit(*image)) { +- entry = findEntryByPath(cfg, image, prefix, NULL); +- if(entry) +- entry->skip = 1; +- return; +- } ++ /* check and see if we're removing the default image */ ++ if (isdigit(*image)) { ++ entry = findEntryByPath(cfg, image, prefix, NULL); ++ if (entry) ++ entry->skip = 1; ++ return; ++ } + +- while ((entry = findEntryByPath(cfg, image, prefix, NULL))) +- entry->skip = 1; ++ while ((entry = findEntryByPath(cfg, image, prefix, NULL))) ++ entry->skip = 1; + } + +-void setDefaultImage(struct grubConfig * config, int hasNew, +- const char * defaultKernelPath, int newIsDefault, +- const char * prefix, int flags, int index) { +- struct singleEntry * entry, * entry2, * newDefault; +- int i, j; +- +- if (newIsDefault) { +- config->defaultImage = 0; +- return; +- } else if ((index >= 0) && config->cfi->defaultIsIndex) { +- if (findEntryByIndex(config, index)) +- config->defaultImage = index; +- else +- config->defaultImage = -1; +- return; +- } else if (defaultKernelPath) { +- i = 0; +- if (findEntryByPath(config, defaultKernelPath, prefix, &i)) { +- config->defaultImage = i; +- } else { +- config->defaultImage = -1; +- return; ++void setDefaultImage(struct grubConfig *config, int hasNew, ++ const char *defaultKernelPath, int newIsDefault, ++ const char *prefix, int flags, int index) ++{ ++ struct singleEntry *entry, *entry2, *newDefault; ++ int i, j; ++ ++ if (newIsDefault) { ++ config->defaultImage = 0; ++ return; ++ } else if ((index >= 0) && config->cfi->defaultIsIndex) { ++ if (findEntryByIndex(config, index)) ++ config->defaultImage = index; ++ else ++ config->defaultImage = -1; ++ return; ++ } else if (defaultKernelPath) { ++ i = 0; ++ if (findEntryByPath(config, defaultKernelPath, prefix, &i)) { ++ config->defaultImage = i; ++ } else { ++ config->defaultImage = -1; ++ return; ++ } + } +- } + +- /* defaultImage now points to what we'd like to use, but before any order +- changes */ +- if ((config->defaultImage == DEFAULT_SAVED) || +- (config->defaultImage == DEFAULT_SAVED_GRUB2)) +- /* default is set to saved, we don't want to change it */ +- return; ++ /* defaultImage now points to what we'd like to use, but before any order ++ changes */ ++ if ((config->defaultImage == DEFAULT_SAVED) || ++ (config->defaultImage == DEFAULT_SAVED_GRUB2)) ++ /* default is set to saved, we don't want to change it */ ++ return; + +- if (config->defaultImage > -1) +- entry = findEntryByIndex(config, config->defaultImage); +- else +- entry = NULL; ++ if (config->defaultImage > -1) ++ entry = findEntryByIndex(config, config->defaultImage); ++ else ++ entry = NULL; + +- if (entry && !entry->skip) { +- /* we can preserve the default */ +- if (hasNew) +- config->defaultImage++; +- +- /* count the number of entries erased before this one */ +- for (j = 0; j < config->defaultImage; j++) { +- entry2 = findEntryByIndex(config, j); +- if (entry2->skip) config->defaultImage--; +- } +- } else if (hasNew) { +- config->defaultImage = 0; +- } else { +- /* Either we just erased the default (or the default line was bad +- * to begin with) and didn't put a new one in. We'll use the first +- * valid image. */ +- newDefault = findTemplate(config, prefix, &config->defaultImage, 1, +- flags); +- if (!newDefault) +- config->defaultImage = -1; +- } +-} ++ if (entry && !entry->skip) { ++ /* we can preserve the default */ ++ if (hasNew) ++ config->defaultImage++; + +-void setFallbackImage(struct grubConfig * config, int hasNew) { +- struct singleEntry * entry, * entry2; +- int j; +- +- if (config->fallbackImage == -1) return; +- +- entry = findEntryByIndex(config, config->fallbackImage); +- if (!entry || entry->skip) { +- config->fallbackImage = -1; +- return; +- } +- +- if (hasNew) +- config->fallbackImage++; +- +- /* count the number of entries erased before this one */ +- for (j = 0; j < config->fallbackImage; j++) { +- entry2 = findEntryByIndex(config, j); +- if (entry2->skip) config->fallbackImage--; +- } ++ /* count the number of entries erased before this one */ ++ for (j = 0; j < config->defaultImage; j++) { ++ entry2 = findEntryByIndex(config, j); ++ if (entry2->skip) ++ config->defaultImage--; ++ } ++ } else if (hasNew) { ++ config->defaultImage = 0; ++ } else { ++ /* Either we just erased the default (or the default line was bad ++ * to begin with) and didn't put a new one in. We'll use the first ++ * valid image. */ ++ newDefault = ++ findTemplate(config, prefix, &config->defaultImage, 1, ++ flags); ++ if (!newDefault) ++ config->defaultImage = -1; ++ } + } + +-void displayEntry(struct singleEntry * entry, const char * prefix, int index) { +- struct singleLine * line; +- char * root = NULL; +- int i; +- +- printf("index=%d\n", index); +- +- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); +- if (!line) { +- printf("non linux entry\n"); +- return; +- } +- +- if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) +- printf("kernel=%s\n", line->elements[1].item); +- else +- printf("kernel=%s%s\n", prefix, line->elements[1].item); +- +- if (line->numElements >= 3) { +- printf("args=\""); +- i = 2; +- while (i < line->numElements) { +- if (!strncmp(line->elements[i].item, "root=", 5)) { +- root = line->elements[i].item + 5; +- } else { +- printf("%s%s", line->elements[i].item, +- line->elements[i].indent); +- } +- +- i++; +- } +- printf("\"\n"); +- } else { +- line = getLineByType(LT_KERNELARGS, entry->lines); +- if (line) { +- char * s; ++void setFallbackImage(struct grubConfig *config, int hasNew) ++{ ++ struct singleEntry *entry, *entry2; ++ int j; + +- printf("args=\""); +- i = 1; +- while (i < line->numElements) { +- if (!strncmp(line->elements[i].item, "root=", 5)) { +- root = line->elements[i].item + 5; +- } else { +- s = line->elements[i].item; ++ if (config->fallbackImage == -1) ++ return; + +- printf("%s%s", s, line->elements[i].indent); +- } ++ entry = findEntryByIndex(config, config->fallbackImage); ++ if (!entry || entry->skip) { ++ config->fallbackImage = -1; ++ return; ++ } + +- i++; +- } ++ if (hasNew) ++ config->fallbackImage++; + +- s = line->elements[i - 1].indent; +- printf("\"\n"); ++ /* count the number of entries erased before this one */ ++ for (j = 0; j < config->fallbackImage; j++) { ++ entry2 = findEntryByIndex(config, j); ++ if (entry2->skip) ++ config->fallbackImage--; + } +- } ++} + +- if (!root) { +- line = getLineByType(LT_ROOT, entry->lines); +- if (line && line->numElements >= 2) +- root=line->elements[1].item; +- } ++void displayEntry(struct singleEntry *entry, const char *prefix, int index) ++{ ++ struct singleLine *line; ++ char *root = NULL; ++ int i; + +- if (root) { +- char * s = alloca(strlen(root) + 1); +- +- strcpy(s, root); +- if (s[strlen(s) - 1] == '"') +- s[strlen(s) - 1] = '\0'; +- /* make sure the root doesn't have a trailing " */ +- printf("root=%s\n", s); +- } ++ printf("index=%d\n", index); + +- line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines); ++ line = ++ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | LT_KERNEL_16, ++ entry->lines); ++ if (!line) { ++ printf("non linux entry\n"); ++ return; ++ } + +- if (line && line->numElements >= 2) { + if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) +- printf("initrd="); ++ printf("kernel=%s\n", line->elements[1].item); + else +- printf("initrd=%s", prefix); +- +- for (i = 1; i < line->numElements; i++) +- printf("%s%s", line->elements[i].item, line->elements[i].indent); +- printf("\n"); +- } +- +- line = getLineByType(LT_TITLE, entry->lines); +- if (line) { +- printf("title=%s\n", line->elements[1].item); +- } else { +- char * title; +- line = getLineByType(LT_MENUENTRY, entry->lines); +- if (line) { +- title = grub2ExtractTitle(line); +- if (title) +- printf("title=%s\n", title); +- } +- } +-} +- +-int isSuseSystem(void) { +- const char * path; +- const static char default_path[] = "/etc/SuSE-release"; +- +- if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL) +- path = default_path; +- +- if (!access(path, R_OK)) +- return 1; +- return 0; +-} ++ printf("kernel=%s%s\n", prefix, line->elements[1].item); ++ ++ if (line->numElements >= 3) { ++ printf("args=\""); ++ i = 2; ++ while (i < line->numElements) { ++ if (!strncmp(line->elements[i].item, "root=", 5)) { ++ root = line->elements[i].item + 5; ++ } else { ++ printf("%s%s", line->elements[i].item, ++ line->elements[i].indent); ++ } + +-int isSuseGrubConf(const char * path) { +- FILE * grubConf; +- char * line = NULL; +- size_t len = 0, res = 0; ++ i++; ++ } ++ printf("\"\n"); ++ } else { ++ line = getLineByType(LT_KERNELARGS, entry->lines); ++ if (line) { ++ char *s; ++ ++ printf("args=\""); ++ i = 1; ++ while (i < line->numElements) { ++ if (!strncmp ++ (line->elements[i].item, "root=", 5)) { ++ root = line->elements[i].item + 5; ++ } else { ++ s = line->elements[i].item; ++ ++ printf("%s%s", s, ++ line->elements[i].indent); ++ } + +- grubConf = fopen(path, "r"); +- if (!grubConf) { +- dbgPrintf("Could not open SuSE configuration file '%s'\n", path); +- return 0; +- } ++ i++; ++ } + +- while ((res = getline(&line, &len, grubConf)) != -1) { +- if (!strncmp(line, "setup", 5)) { +- fclose(grubConf); +- free(line); +- return 1; ++ s = line->elements[i - 1].indent; ++ printf("\"\n"); ++ } + } +- } + +- dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n", +- path); ++ if (!root) { ++ line = getLineByType(LT_ROOT, entry->lines); ++ if (line && line->numElements >= 2) ++ root = line->elements[1].item; ++ } + +- fclose(grubConf); +- free(line); +- return 0; +-} ++ if (root) { ++ char *s = alloca(strlen(root) + 1); + +-int suseGrubConfGetLba(const char * path, int * lbaPtr) { +- FILE * grubConf; +- char * line = NULL; +- size_t res = 0, len = 0; ++ strcpy(s, root); ++ if (s[strlen(s) - 1] == '"') ++ s[strlen(s) - 1] = '\0'; ++ /* make sure the root doesn't have a trailing " */ ++ printf("root=%s\n", s); ++ } + +- if (!path) return 1; +- if (!lbaPtr) return 1; ++ line = ++ getLineByType(LT_INITRD | LT_INITRD_EFI | LT_INITRD_16, ++ entry->lines); + +- grubConf = fopen(path, "r"); +- if (!grubConf) return 1; ++ if (line && line->numElements >= 2) { ++ if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) ++ printf("initrd="); ++ else ++ printf("initrd=%s", prefix); + +- while ((res = getline(&line, &len, grubConf)) != -1) { +- if (line[res - 1] == '\n') +- line[res - 1] = '\0'; +- else if (len > res) +- line[res] = '\0'; +- else { +- line = realloc(line, res + 1); +- line[res] = '\0'; ++ for (i = 1; i < line->numElements; i++) ++ printf("%s%s", line->elements[i].item, ++ line->elements[i].indent); ++ printf("\n"); + } + +- if (!strncmp(line, "setup", 5)) { +- if (strstr(line, "--force-lba")) { +- *lbaPtr = 1; +- } else { +- *lbaPtr = 0; +- } +- dbgPrintf("lba: %i\n", *lbaPtr); +- break; ++ line = getLineByType(LT_TITLE, entry->lines); ++ if (line) { ++ printf("title=%s\n", line->elements[1].item); ++ } else { ++ char *title; ++ line = getLineByType(LT_MENUENTRY, entry->lines); ++ if (line) { ++ title = grub2ExtractTitle(line); ++ if (title) ++ printf("title=%s\n", title); ++ } + } +- } +- +- free(line); +- fclose(grubConf); +- return 0; + } + +-int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) { +- FILE * grubConf; +- char * line = NULL; +- size_t res = 0, len = 0; +- char * lastParamPtr = NULL; +- char * secLastParamPtr = NULL; +- char installDeviceNumber = '\0'; +- char * bounds = NULL; +- +- if (!path) return 1; +- if (!devicePtr) return 1; +- +- grubConf = fopen(path, "r"); +- if (!grubConf) return 1; +- +- while ((res = getline(&line, &len, grubConf)) != -1) { +- if (strncmp(line, "setup", 5)) +- continue; +- +- if (line[res - 1] == '\n') +- line[res - 1] = '\0'; +- else if (len > res) +- line[res] = '\0'; +- else { +- line = realloc(line, res + 1); +- line[res] = '\0'; +- } +- +- lastParamPtr = bounds = line + res; ++int isSuseSystem(void) ++{ ++ const char *path; ++ const static char default_path[] = "/etc/SuSE-release"; + +- /* Last parameter in grub may be an optional IMAGE_DEVICE */ +- while (!isspace(*lastParamPtr)) +- lastParamPtr--; +- lastParamPtr++; ++ if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL) ++ path = default_path; + +- secLastParamPtr = lastParamPtr - 2; +- dbgPrintf("lastParamPtr: %s\n", lastParamPtr); ++ if (!access(path, R_OK)) ++ return 1; ++ return 0; ++} + +- if (lastParamPtr + 3 > bounds) { +- dbgPrintf("lastParamPtr going over boundary"); +- fclose(grubConf); +- free(line); +- return 1; ++int isSuseGrubConf(const char *path) ++{ ++ FILE *grubConf; ++ char *line = NULL; ++ size_t len = 0, res = 0; ++ ++ grubConf = fopen(path, "r"); ++ if (!grubConf) { ++ dbgPrintf("Could not open SuSE configuration file '%s'\n", ++ path); ++ return 0; + } +- if (!strncmp(lastParamPtr, "(hd", 3)) +- lastParamPtr += 3; +- dbgPrintf("lastParamPtr: %c\n", *lastParamPtr); + +- /* +- * Second last parameter will decide wether last parameter is +- * an IMAGE_DEVICE or INSTALL_DEVICE +- */ +- while (!isspace(*secLastParamPtr)) +- secLastParamPtr--; +- secLastParamPtr++; +- +- if (secLastParamPtr + 3 > bounds) { +- dbgPrintf("secLastParamPtr going over boundary"); +- fclose(grubConf); +- free(line); +- return 1; +- } +- dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr); +- if (!strncmp(secLastParamPtr, "(hd", 3)) { +- secLastParamPtr += 3; +- dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr); +- installDeviceNumber = *secLastParamPtr; +- } else { +- installDeviceNumber = *lastParamPtr; ++ while ((res = getline(&line, &len, grubConf)) != -1) { ++ if (!strncmp(line, "setup", 5)) { ++ fclose(grubConf); ++ free(line); ++ return 1; ++ } + } + +- *devicePtr = malloc(6); +- snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber); +- dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber); ++ dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n", ++ path); ++ + fclose(grubConf); + free(line); + return 0; +- } +- +- free(line); +- fclose(grubConf); +- return 1; + } + +-int grubGetBootFromDeviceMap(const char * device, +- char ** bootPtr) { +- FILE * deviceMap; +- char * line = NULL; +- size_t res = 0, len = 0; +- char * devicePtr; +- char * bounds = NULL; +- const char * path; +- const static char default_path[] = "/boot/grub/device.map"; +- +- if (!device) return 1; +- if (!bootPtr) return 1; +- +- if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL) +- path = default_path; +- +- dbgPrintf("opening grub device.map file from: %s\n", path); +- deviceMap = fopen(path, "r"); +- if (!deviceMap) +- return 1; +- +- while ((res = getline(&line, &len, deviceMap)) != -1) { +- if (!strncmp(line, "#", 1)) +- continue; +- +- if (line[res - 1] == '\n') +- line[res - 1] = '\0'; +- else if (len > res) +- line[res] = '\0'; +- else { +- line = realloc(line, res + 1); +- line[res] = '\0'; +- } ++int suseGrubConfGetLba(const char *path, int *lbaPtr) ++{ ++ FILE *grubConf; ++ char *line = NULL; ++ size_t res = 0, len = 0; + +- devicePtr = line; +- bounds = line + res; ++ if (!path) ++ return 1; ++ if (!lbaPtr) ++ return 1; + +- while ((isspace(*line) && ((devicePtr + 1) <= bounds))) +- devicePtr++; +- dbgPrintf("device: %s\n", devicePtr); ++ grubConf = fopen(path, "r"); ++ if (!grubConf) ++ return 1; + +- if (!strncmp(devicePtr, device, strlen(device))) { +- devicePtr += strlen(device); +- while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds)) +- devicePtr++; ++ while ((res = getline(&line, &len, grubConf)) != -1) { ++ if (line[res - 1] == '\n') ++ line[res - 1] = '\0'; ++ else if (len > res) ++ line[res] = '\0'; ++ else { ++ line = realloc(line, res + 1); ++ line[res] = '\0'; ++ } + +- *bootPtr = strdup(devicePtr); +- break; ++ if (!strncmp(line, "setup", 5)) { ++ if (strstr(line, "--force-lba")) { ++ *lbaPtr = 1; ++ } else { ++ *lbaPtr = 0; ++ } ++ dbgPrintf("lba: %i\n", *lbaPtr); ++ break; ++ } + } +- } + +- free(line); +- fclose(deviceMap); +- return 0; ++ free(line); ++ fclose(grubConf); ++ return 0; + } + +-int suseGrubConfGetBoot(const char * path, char ** bootPtr) { +- char * grubDevice; ++int suseGrubConfGetInstallDevice(const char *path, char **devicePtr) ++{ ++ FILE *grubConf; ++ char *line = NULL; ++ size_t res = 0, len = 0; ++ char *lastParamPtr = NULL; ++ char *secLastParamPtr = NULL; ++ char installDeviceNumber = '\0'; ++ char *bounds = NULL; ++ ++ if (!path) ++ return 1; ++ if (!devicePtr) ++ return 1; + +- if (suseGrubConfGetInstallDevice(path, &grubDevice)) +- dbgPrintf("error looking for grub installation device\n"); +- else +- dbgPrintf("grubby installation device: %s\n", grubDevice); ++ grubConf = fopen(path, "r"); ++ if (!grubConf) ++ return 1; + +- if (grubGetBootFromDeviceMap(grubDevice, bootPtr)) +- dbgPrintf("error looking for grub boot device\n"); +- else +- dbgPrintf("grubby boot device: %s\n", *bootPtr); ++ while ((res = getline(&line, &len, grubConf)) != -1) { ++ if (strncmp(line, "setup", 5)) ++ continue; ++ ++ if (line[res - 1] == '\n') ++ line[res - 1] = '\0'; ++ else if (len > res) ++ line[res] = '\0'; ++ else { ++ line = realloc(line, res + 1); ++ line[res] = '\0'; ++ } + +- free(grubDevice); +- return 0; +-} ++ lastParamPtr = bounds = line + res; + +-int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) { +- /* +- * This SuSE grub configuration file at this location is not your average +- * grub configuration file, but instead the grub commands used to setup +- * grub on that system. +- */ +- const char * path; +- const static char default_path[] = "/etc/grub.conf"; ++ /* Last parameter in grub may be an optional IMAGE_DEVICE */ ++ while (!isspace(*lastParamPtr)) ++ lastParamPtr--; ++ lastParamPtr++; + +- if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL) +- path = default_path; ++ secLastParamPtr = lastParamPtr - 2; ++ dbgPrintf("lastParamPtr: %s\n", lastParamPtr); + +- if (!isSuseGrubConf(path)) return 1; ++ if (lastParamPtr + 3 > bounds) { ++ dbgPrintf("lastParamPtr going over boundary"); ++ fclose(grubConf); ++ free(line); ++ return 1; ++ } ++ if (!strncmp(lastParamPtr, "(hd", 3)) ++ lastParamPtr += 3; ++ dbgPrintf("lastParamPtr: %c\n", *lastParamPtr); + +- if (lbaPtr) { +- *lbaPtr = 0; +- if (suseGrubConfGetLba(path, lbaPtr)) +- return 1; +- } ++ /* ++ * Second last parameter will decide wether last parameter is ++ * an IMAGE_DEVICE or INSTALL_DEVICE ++ */ ++ while (!isspace(*secLastParamPtr)) ++ secLastParamPtr--; ++ secLastParamPtr++; ++ ++ if (secLastParamPtr + 3 > bounds) { ++ dbgPrintf("secLastParamPtr going over boundary"); ++ fclose(grubConf); ++ free(line); ++ return 1; ++ } ++ dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr); ++ if (!strncmp(secLastParamPtr, "(hd", 3)) { ++ secLastParamPtr += 3; ++ dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr); ++ installDeviceNumber = *secLastParamPtr; ++ } else { ++ installDeviceNumber = *lastParamPtr; ++ } + +- if (bootPtr) { +- *bootPtr = NULL; +- suseGrubConfGetBoot(path, bootPtr); +- } ++ *devicePtr = malloc(6); ++ snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber); ++ dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber); ++ fclose(grubConf); ++ free(line); ++ return 0; ++ } + +- return 0; ++ free(line); ++ fclose(grubConf); ++ return 1; + } + +-int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) { +- FILE * in; +- char buf[1024]; +- char * chptr; +- char * start; +- char * param; +- +- in = fopen("/etc/sysconfig/grub", "r"); +- if (!in) return 1; ++int grubGetBootFromDeviceMap(const char *device, char **bootPtr) ++{ ++ FILE *deviceMap; ++ char *line = NULL; ++ size_t res = 0, len = 0; ++ char *devicePtr; ++ char *bounds = NULL; ++ const char *path; ++ const static char default_path[] = "/boot/grub/device.map"; ++ ++ if (!device) ++ return 1; ++ if (!bootPtr) ++ return 1; + +- if (lbaPtr) *lbaPtr = 0; +- if (bootPtr) *bootPtr = NULL; ++ if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL) ++ path = default_path; + +- while (fgets(buf, sizeof(buf), in)) { +- start = buf; +- while (isspace(*start)) start++; +- if (*start == '#') continue; ++ dbgPrintf("opening grub device.map file from: %s\n", path); ++ deviceMap = fopen(path, "r"); ++ if (!deviceMap) ++ return 1; + +- chptr = strchr(start, '='); +- if (!chptr) continue; +- chptr--; +- while (*chptr && isspace(*chptr)) chptr--; +- chptr++; +- *chptr = '\0'; ++ while ((res = getline(&line, &len, deviceMap)) != -1) { ++ if (!strncmp(line, "#", 1)) ++ continue; ++ ++ if (line[res - 1] == '\n') ++ line[res - 1] = '\0'; ++ else if (len > res) ++ line[res] = '\0'; ++ else { ++ line = realloc(line, res + 1); ++ line[res] = '\0'; ++ } + +- param = chptr + 1; +- while (*param && isspace(*param)) param++; +- if (*param == '=') { +- param++; +- while (*param && isspace(*param)) param++; +- } ++ devicePtr = line; ++ bounds = line + res; + +- chptr = param; +- while (*chptr && !isspace(*chptr)) chptr++; +- *chptr = '\0'; ++ while ((isspace(*line) && ((devicePtr + 1) <= bounds))) ++ devicePtr++; ++ dbgPrintf("device: %s\n", devicePtr); + +- if (!strcmp(start, "forcelba") && !strcmp(param, "1") && lbaPtr) +- *lbaPtr = 1; +- else if (!strcmp(start, "boot") && bootPtr) +- *bootPtr = strdup(param); +- } ++ if (!strncmp(devicePtr, device, strlen(device))) { ++ devicePtr += strlen(device); ++ while (isspace(*devicePtr) ++ && ((devicePtr + 1) <= bounds)) ++ devicePtr++; + +- fclose(in); ++ *bootPtr = strdup(devicePtr); ++ break; ++ } ++ } + +- return 0; ++ free(line); ++ fclose(deviceMap); ++ return 0; + } + +-void dumpSysconfigGrub(void) { +- char * boot = NULL; +- int lba; ++int suseGrubConfGetBoot(const char *path, char **bootPtr) ++{ ++ char *grubDevice; + +- if (isSuseSystem()) { +- if (parseSuseGrubConf(&lba, &boot)) { +- free(boot); +- return; +- } +- } else { +- if (parseSysconfigGrub(&lba, &boot)) { +- free(boot); +- return; +- } +- } ++ if (suseGrubConfGetInstallDevice(path, &grubDevice)) ++ dbgPrintf("error looking for grub installation device\n"); ++ else ++ dbgPrintf("grubby installation device: %s\n", grubDevice); + +- if (lba) printf("lba\n"); +- if (boot) { +- printf("boot=%s\n", boot); +- free(boot); +- } +-} ++ if (grubGetBootFromDeviceMap(grubDevice, bootPtr)) ++ dbgPrintf("error looking for grub boot device\n"); ++ else ++ dbgPrintf("grubby boot device: %s\n", *bootPtr); + +-int displayInfo(struct grubConfig * config, char * kernel, +- const char * prefix) { +- int i = 0; +- struct singleEntry * entry; +- struct singleLine * line; ++ free(grubDevice); ++ return 0; ++} + +- entry = findEntryByPath(config, kernel, prefix, &i); +- if (!entry) { +- fprintf(stderr, _("grubby: kernel not found\n")); +- return 1; +- } ++int parseSuseGrubConf(int *lbaPtr, char **bootPtr) ++{ ++ /* ++ * This SuSE grub configuration file at this location is not your average ++ * grub configuration file, but instead the grub commands used to setup ++ * grub on that system. ++ */ ++ const char *path; ++ const static char default_path[] = "/etc/grub.conf"; + +- /* this is a horrible hack to support /etc/sysconfig/grub; there must +- be a better way */ +- if (config->cfi == &grubConfigType) { +- dumpSysconfigGrub(); +- } else { +- line = getLineByType(LT_BOOT, config->theLines); +- if (line && line->numElements >= 1) { +- printf("boot=%s\n", line->elements[1].item); +- } ++ if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL) ++ path = default_path; + +- line = getLineByType(LT_LBA, config->theLines); +- if (line) printf("lba\n"); +- } ++ if (!isSuseGrubConf(path)) ++ return 1; + +- displayEntry(entry, prefix, i); ++ if (lbaPtr) { ++ *lbaPtr = 0; ++ if (suseGrubConfGetLba(path, lbaPtr)) ++ return 1; ++ } + +- i++; +- while ((entry = findEntryByPath(config, kernel, prefix, &i))) { +- displayEntry(entry, prefix, i); +- i++; +- } ++ if (bootPtr) { ++ *bootPtr = NULL; ++ suseGrubConfGetBoot(path, bootPtr); ++ } + +- return 0; ++ return 0; + } + +-struct singleLine * addLineTmpl(struct singleEntry * entry, +- struct singleLine * tmplLine, +- struct singleLine * prevLine, +- const char * val, +- struct configFileInfo * cfi) ++int parseSysconfigGrub(int *lbaPtr, char **bootPtr) + { +- struct singleLine * newLine = lineDup(tmplLine); +- +- if (isEfi && cfi == &grub2ConfigType) { +- enum lineType_e old = newLine->type; +- newLine->type = preferredLineType(newLine->type, cfi); +- if (old != newLine->type) +- newLine->elements[0].item = getKeyByType(newLine->type, cfi); +- } +- +- if (val) { +- /* override the inherited value with our own. +- * This is a little weak because it only applies to elements[1] +- */ +- if (newLine->numElements > 1) +- removeElement(newLine, 1); +- insertElement(newLine, val, 1, cfi); +- +- /* but try to keep the rootspec from the template... sigh */ +- if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) { +- char * rootspec = getRootSpecifier(tmplLine->elements[1].item); +- if (rootspec != NULL) { +- free(newLine->elements[1].item); +- newLine->elements[1].item = +- sdupprintf("%s%s", rootspec, val); +- } +- } +- } +- +- dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ? +- newLine->elements[0].item : ""); +- +- if (!entry->lines) { +- /* first one on the list */ +- entry->lines = newLine; +- } else if (prevLine) { +- /* add after prevLine */ +- newLine->next = prevLine->next; +- prevLine->next = newLine; +- } +- +- return newLine; +-} ++ FILE *in; ++ char buf[1024]; ++ char *chptr; ++ char *start; ++ char *param; ++ ++ in = fopen("/etc/sysconfig/grub", "r"); ++ if (!in) ++ return 1; + +-/* val may be NULL */ +-struct singleLine * addLine(struct singleEntry * entry, +- struct configFileInfo * cfi, +- enum lineType_e type, char * defaultIndent, +- const char * val) { +- struct singleLine * line, * prev; +- struct keywordTypes * kw; +- struct singleLine tmpl; +- +- /* NB: This function shouldn't allocate items on the heap, rather on the +- * stack since it calls addLineTmpl which will make copies. +- */ +- if (type == LT_TITLE && cfi->titleBracketed) { +- /* we're doing a bracketed title (zipl) */ +- tmpl.type = type; +- tmpl.numElements = 1; +- tmpl.elements = alloca(sizeof(*tmpl.elements)); +- tmpl.elements[0].item = alloca(strlen(val)+3); +- sprintf(tmpl.elements[0].item, "[%s]", val); +- tmpl.elements[0].indent = ""; +- val = NULL; +- } else if (type == LT_MENUENTRY) { +- char *lineend = "--class gnu-linux --class gnu --class os {"; +- if (!val) { +- fprintf(stderr, "Line type LT_MENUENTRY requires a value\n"); +- abort(); +- } +- kw = getKeywordByType(type, cfi); +- if (!kw) { +- fprintf(stderr, "Looking up keyword for unknown type %d\n", type); +- abort(); +- } +- tmpl.indent = ""; +- tmpl.type = type; +- tmpl.numElements = 3; +- tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements); +- tmpl.elements[0].item = kw->key; +- tmpl.elements[0].indent = alloca(2); +- sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); +- tmpl.elements[1].item = (char *)val; +- tmpl.elements[1].indent = alloca(2); +- sprintf(tmpl.elements[1].indent, "%c", kw->nextChar); +- tmpl.elements[2].item = alloca(strlen(lineend)+1); +- strcpy(tmpl.elements[2].item, lineend); +- tmpl.elements[2].indent = ""; +- } else { +- kw = getKeywordByType(type, cfi); +- if (!kw) { +- fprintf(stderr, "Looking up keyword for unknown type %d\n", type); +- abort(); +- } +- tmpl.type = type; +- tmpl.numElements = val ? 2 : 1; +- tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements); +- tmpl.elements[0].item = kw->key; +- tmpl.elements[0].indent = alloca(2); +- sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); +- if (val) { +- tmpl.elements[1].item = (char *)val; +- tmpl.elements[1].indent = ""; +- } +- } +- +- /* The last non-empty line gives us the indention to us and the line +- to insert after. Note that comments are considered empty lines, which +- may not be ideal? If there are no lines or we are looking at the +- first line, we use defaultIndent (the first line is normally indented +- differently from the rest) */ +- for (line = entry->lines, prev = NULL; line; line = line->next) { +- if (line->numElements) prev = line; +- /* fall back on the last line if prev isn't otherwise set */ +- if (!line->next && !prev) prev = line; +- } +- +- struct singleLine *menuEntry; +- menuEntry = getLineByType(LT_MENUENTRY, entry->lines); +- if (tmpl.type == LT_ENTRY_END) { +- if (menuEntry) +- tmpl.indent = menuEntry->indent; +- else +- tmpl.indent = defaultIndent ?: ""; +- } else if (tmpl.type != LT_MENUENTRY) { +- if (menuEntry) +- tmpl.indent = "\t"; +- else if (prev == entry->lines) +- tmpl.indent = defaultIndent ?: ""; +- else +- tmpl.indent = prev->indent; +- } ++ if (lbaPtr) ++ *lbaPtr = 0; ++ if (bootPtr) ++ *bootPtr = NULL; ++ ++ while (fgets(buf, sizeof(buf), in)) { ++ start = buf; ++ while (isspace(*start)) ++ start++; ++ if (*start == '#') ++ continue; ++ ++ chptr = strchr(start, '='); ++ if (!chptr) ++ continue; ++ chptr--; ++ while (*chptr && isspace(*chptr)) ++ chptr--; ++ chptr++; ++ *chptr = '\0'; ++ ++ param = chptr + 1; ++ while (*param && isspace(*param)) ++ param++; ++ if (*param == '=') { ++ param++; ++ while (*param && isspace(*param)) ++ param++; ++ } + +- return addLineTmpl(entry, &tmpl, prev, val, cfi); +-} ++ chptr = param; ++ while (*chptr && !isspace(*chptr)) ++ chptr++; ++ *chptr = '\0'; ++ ++ if (!strcmp(start, "forcelba") && !strcmp(param, "1") && lbaPtr) ++ *lbaPtr = 1; ++ else if (!strcmp(start, "boot") && bootPtr) ++ *bootPtr = strdup(param); ++ } + +-void removeLine(struct singleEntry * entry, struct singleLine * line) { +- struct singleLine * prev; +- int i; +- +- for (i = 0; i < line->numElements; i++) { +- free(line->elements[i].item); +- free(line->elements[i].indent); +- } +- free(line->elements); +- free(line->indent); +- +- if (line == entry->lines) { +- entry->lines = line->next; +- } else { +- prev = entry->lines; +- while (prev->next != line) prev = prev->next; +- prev->next = line->next; +- } +- +- free(line); ++ fclose(in); ++ ++ return 0; + } + +-static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi) ++void dumpSysconfigGrub(void) + { +- struct singleLine newLine = { +- .indent = tmplLine->indent, +- .type = tmplLine->type, +- .next = tmplLine->next, +- }; +- int firstQuotedItem = -1; +- int quoteLen = 0; +- int j; +- int element = 0; +- char *c; +- +- c = malloc(strlen(tmplLine->elements[0].item) + 1); +- strcpy(c, tmplLine->elements[0].item); +- insertElement(&newLine, c, element++, cfi); +- free(c); +- c = NULL; +- +- for (j = 1; j < tmplLine->numElements; j++) { +- if (firstQuotedItem == -1) { +- quoteLen += strlen(tmplLine->elements[j].item); +- +- if (isquote(tmplLine->elements[j].item[0])) { +- firstQuotedItem = j; +- quoteLen += strlen(tmplLine->elements[j].indent); +- } else { +- c = malloc(quoteLen + 1); +- strcpy(c, tmplLine->elements[j].item); +- insertElement(&newLine, c, element++, cfi); +- free(c); +- quoteLen = 0; +- } ++ char *boot = NULL; ++ int lba; ++ ++ if (isSuseSystem()) { ++ if (parseSuseGrubConf(&lba, &boot)) { ++ free(boot); ++ return; ++ } + } else { +- int itemlen = strlen(tmplLine->elements[j].item); +- quoteLen += itemlen; +- quoteLen += strlen(tmplLine->elements[j].indent); +- +- if (isquote(tmplLine->elements[j].item[itemlen - 1])) { +- c = malloc(quoteLen + 1); +- c[0] = '\0'; +- for (int i = firstQuotedItem; i < j+1; i++) { +- strcat(c, tmplLine->elements[i].item); +- strcat(c, tmplLine->elements[i].indent); ++ if (parseSysconfigGrub(&lba, &boot)) { ++ free(boot); ++ return; + } +- insertElement(&newLine, c, element++, cfi); +- free(c); +- +- firstQuotedItem = -1; +- quoteLen = 0; +- } +- } +- } +- while (tmplLine->numElements) +- removeElement(tmplLine, 0); +- if (tmplLine->elements) +- free(tmplLine->elements); +- +- tmplLine->numElements = newLine.numElements; +- tmplLine->elements = newLine.elements; +-} ++ } + +-static void insertElement(struct singleLine * line, +- const char * item, int insertHere, +- struct configFileInfo * cfi) +-{ +- struct keywordTypes * kw; +- char indent[2] = ""; +- +- /* sanity check */ +- if (insertHere > line->numElements) { +- dbgPrintf("insertElement() adjusting insertHere from %d to %d\n", +- insertHere, line->numElements); +- insertHere = line->numElements; +- } +- +- line->elements = realloc(line->elements, (line->numElements + 1) * +- sizeof(*line->elements)); +- memmove(&line->elements[insertHere+1], +- &line->elements[insertHere], +- (line->numElements - insertHere) * +- sizeof(*line->elements)); +- line->elements[insertHere].item = strdup(item); +- +- kw = getKeywordByType(line->type, cfi); +- +- if (line->numElements == 0) { +- indent[0] = '\0'; +- } else if (insertHere == 0) { +- indent[0] = kw->nextChar; +- } else if (kw->separatorChar != '\0') { +- indent[0] = kw->separatorChar; +- } else { +- indent[0] = ' '; +- } +- +- if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') { +- /* move the end-of-line forward */ +- line->elements[insertHere].indent = +- line->elements[insertHere-1].indent; +- line->elements[insertHere-1].indent = strdup(indent); +- } else { +- line->elements[insertHere].indent = strdup(indent); +- } +- +- line->numElements++; +- +- dbgPrintf("insertElement(%s, '%s%s', %d)\n", +- line->elements[0].item, +- line->elements[insertHere].item, +- line->elements[insertHere].indent, +- insertHere); ++ if (lba) ++ printf("lba\n"); ++ if (boot) { ++ printf("boot=%s\n", boot); ++ free(boot); ++ } + } + +-static void removeElement(struct singleLine * line, int removeHere) { +- int i; ++int displayInfo(struct grubConfig *config, char *kernel, const char *prefix) ++{ ++ int i = 0; ++ struct singleEntry *entry; ++ struct singleLine *line; + +- /* sanity check */ +- if (removeHere >= line->numElements) return; ++ entry = findEntryByPath(config, kernel, prefix, &i); ++ if (!entry) { ++ fprintf(stderr, _("grubby: kernel not found\n")); ++ return 1; ++ } + +- dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item, +- removeHere, line->elements[removeHere].item); ++ /* this is a horrible hack to support /etc/sysconfig/grub; there must ++ be a better way */ ++ if (config->cfi == &grubConfigType) { ++ dumpSysconfigGrub(); ++ } else { ++ line = getLineByType(LT_BOOT, config->theLines); ++ if (line && line->numElements >= 1) { ++ printf("boot=%s\n", line->elements[1].item); ++ } + +- free(line->elements[removeHere].item); ++ line = getLineByType(LT_LBA, config->theLines); ++ if (line) ++ printf("lba\n"); ++ } + +- if (removeHere > 1) { +- /* previous argument gets this argument's post-indentation */ +- free(line->elements[removeHere-1].indent); +- line->elements[removeHere-1].indent = +- line->elements[removeHere].indent; +- } else { +- free(line->elements[removeHere].indent); +- } ++ displayEntry(entry, prefix, i); + +- /* now collapse the array, but don't bother to realloc smaller */ +- for (i = removeHere; i < line->numElements - 1; i++) +- line->elements[i] = line->elements[i + 1]; ++ i++; ++ while ((entry = findEntryByPath(config, kernel, prefix, &i))) { ++ displayEntry(entry, prefix, i); ++ i++; ++ } + +- line->numElements--; ++ return 0; + } + +-int argMatch(const char * one, const char * two) { +- char * first, * second; +- char * chptr; ++struct singleLine *addLineTmpl(struct singleEntry *entry, ++ struct singleLine *tmplLine, ++ struct singleLine *prevLine, ++ const char *val, struct configFileInfo *cfi) ++{ ++ struct singleLine *newLine = lineDup(tmplLine); ++ ++ if (isEfi && cfi == &grub2ConfigType) { ++ enum lineType_e old = newLine->type; ++ newLine->type = preferredLineType(newLine->type, cfi); ++ if (old != newLine->type) ++ newLine->elements[0].item = ++ getKeyByType(newLine->type, cfi); ++ } + +- first = strcpy(alloca(strlen(one) + 1), one); +- second = strcpy(alloca(strlen(two) + 1), two); ++ if (val) { ++ /* override the inherited value with our own. ++ * This is a little weak because it only applies to elements[1] ++ */ ++ if (newLine->numElements > 1) ++ removeElement(newLine, 1); ++ insertElement(newLine, val, 1, cfi); ++ ++ /* but try to keep the rootspec from the template... sigh */ ++ if (tmplLine-> ++ type & (LT_HYPER | LT_KERNEL | LT_MBMODULE | LT_INITRD | ++ LT_KERNEL_EFI | LT_INITRD_EFI | LT_KERNEL_16 | ++ LT_INITRD_16)) { ++ char *rootspec = ++ getRootSpecifier(tmplLine->elements[1].item); ++ if (rootspec != NULL) { ++ free(newLine->elements[1].item); ++ newLine->elements[1].item = ++ sdupprintf("%s%s", rootspec, val); ++ } ++ } ++ } + +- chptr = strchr(first, '='); +- if (chptr) *chptr = '\0'; ++ dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ? ++ newLine->elements[0].item : ""); + +- chptr = strchr(second, '='); +- if (chptr) *chptr = '\0'; ++ if (!entry->lines) { ++ /* first one on the list */ ++ entry->lines = newLine; ++ } else if (prevLine) { ++ /* add after prevLine */ ++ newLine->next = prevLine->next; ++ prevLine->next = newLine; ++ } + +- return strcmp(first, second); ++ return newLine; + } + +-int updateActualImage(struct grubConfig * cfg, const char * image, +- const char * prefix, const char * addArgs, +- const char * removeArgs, int multibootArgs) { +- struct singleEntry * entry; +- struct singleLine * line, * rootLine; +- int index = 0; +- int i, k; +- const char ** newArgs, ** oldArgs; +- const char ** arg; +- int useKernelArgs, useRoot; +- int firstElement; +- int *usedElements; +- int doreplace; +- +- if (!image) return 0; +- +- if (!addArgs) { +- newArgs = malloc(sizeof(*newArgs)); +- *newArgs = NULL; +- } else { +- if (poptParseArgvString(addArgs, NULL, &newArgs)) { +- fprintf(stderr, +- _("grubby: error separating arguments '%s'\n"), addArgs); +- return 1; +- } +- } +- +- if (!removeArgs) { +- oldArgs = malloc(sizeof(*oldArgs)); +- *oldArgs = NULL; +- } else { +- if (poptParseArgvString(removeArgs, NULL, &oldArgs)) { +- fprintf(stderr, +- _("grubby: error separating arguments '%s'\n"), removeArgs); +- free(newArgs); +- return 1; +- } +- } +- +- +- useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi) +- && (!multibootArgs || cfg->cfi->mbConcatArgs)); +- +- useRoot = (getKeywordByType(LT_ROOT, cfg->cfi) +- && !multibootArgs); +- +- for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { +- +- if (multibootArgs && !entry->multiboot) +- continue; +- +- /* Determine where to put the args. If this config supports +- * LT_KERNELARGS, use that. Otherwise use +- * LT_HYPER/LT_KERNEL/LT_MBMODULE lines. +- */ +- if (useKernelArgs) { +- line = getLineByType(LT_KERNELARGS, entry->lines); +- if (!line) { +- /* no LT_KERNELARGS, need to add it */ +- line = addLine(entry, cfg->cfi, LT_KERNELARGS, +- cfg->secondaryIndent, NULL); +- } +- firstElement = 1; +- +- } else if (multibootArgs) { +- line = getLineByType(LT_HYPER, entry->lines); +- if (!line) { +- /* a multiboot entry without LT_HYPER? */ +- continue; +- } +- firstElement = 2; +- +- } else { +- line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); +- if (!line) { +- /* no LT_KERNEL or LT_MBMODULE in this entry? */ +- continue; +- } +- firstElement = 2; +- } ++/* val may be NULL */ ++struct singleLine *addLine(struct singleEntry *entry, ++ struct configFileInfo *cfi, ++ enum lineType_e type, char *defaultIndent, ++ const char *val) ++{ ++ struct singleLine *line, *prev; ++ struct keywordTypes *kw; ++ struct singleLine tmpl; + +- /* handle the elilo case which does: +- * append="hypervisor args -- kernel args" ++ /* NB: This function shouldn't allocate items on the heap, rather on the ++ * stack since it calls addLineTmpl which will make copies. + */ +- if (entry->multiboot && cfg->cfi->mbConcatArgs) { +- /* this is a multiboot entry, make sure there's +- * -- on the args line +- */ +- for (i = firstElement; i < line->numElements; i++) { +- if (!strcmp(line->elements[i].item, "--")) +- break; +- } +- if (i == line->numElements) { +- /* assume all existing args are kernel args, +- * prepend -- to make it official +- */ +- insertElement(line, "--", firstElement, cfg->cfi); +- i = firstElement; +- } +- if (!multibootArgs) { +- /* kernel args start after the -- */ +- firstElement = i + 1; +- } +- } else if (cfg->cfi->mbConcatArgs) { +- /* this is a non-multiboot entry, remove hyper args */ +- for (i = firstElement; i < line->numElements; i++) { +- if (!strcmp(line->elements[i].item, "--")) +- break; +- } +- if (i < line->numElements) { +- /* remove args up to -- */ +- while (strcmp(line->elements[firstElement].item, "--")) +- removeElement(line, firstElement); +- /* remove -- */ +- removeElement(line, firstElement); +- } +- } +- +- usedElements = calloc(line->numElements, sizeof(*usedElements)); +- +- for (k = 0, arg = newArgs; *arg; arg++, k++) { +- +- doreplace = 1; +- for (i = firstElement; i < line->numElements; i++) { +- if (multibootArgs && cfg->cfi->mbConcatArgs && +- !strcmp(line->elements[i].item, "--")) +- { +- /* reached the end of hyper args, insert here */ +- doreplace = 0; +- break; ++ if (type == LT_TITLE && cfi->titleBracketed) { ++ /* we're doing a bracketed title (zipl) */ ++ tmpl.type = type; ++ tmpl.numElements = 1; ++ tmpl.elements = alloca(sizeof(*tmpl.elements)); ++ tmpl.elements[0].item = alloca(strlen(val) + 3); ++ sprintf(tmpl.elements[0].item, "[%s]", val); ++ tmpl.elements[0].indent = ""; ++ val = NULL; ++ } else if (type == LT_MENUENTRY) { ++ char *lineend = "--class gnu-linux --class gnu --class os {"; ++ if (!val) { ++ fprintf(stderr, ++ "Line type LT_MENUENTRY requires a value\n"); ++ abort(); + } +- if (usedElements[i]) +- continue; +- if (!argMatch(line->elements[i].item, *arg)) { +- usedElements[i]=1; +- break; +- } +- } +- +- if (i < line->numElements && doreplace) { +- /* direct replacement */ +- free(line->elements[i].item); +- line->elements[i].item = strdup(*arg); +- +- } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) { +- /* root= replacement */ +- rootLine = getLineByType(LT_ROOT, entry->lines); +- if (rootLine) { +- free(rootLine->elements[1].item); +- rootLine->elements[1].item = strdup(*arg + 5); +- } else { +- rootLine = addLine(entry, cfg->cfi, LT_ROOT, +- cfg->secondaryIndent, *arg + 5); ++ kw = getKeywordByType(type, cfi); ++ if (!kw) { ++ fprintf(stderr, ++ "Looking up keyword for unknown type %d\n", ++ type); ++ abort(); + } +- } +- +- else { +- /* insert/append */ +- insertElement(line, *arg, i, cfg->cfi); +- usedElements = realloc(usedElements, line->numElements * +- sizeof(*usedElements)); +- memmove(&usedElements[i + 1], &usedElements[i], +- line->numElements - i - 1); +- usedElements[i] = 1; +- +- /* if we updated a root= here even though there is a +- LT_ROOT available we need to remove the LT_ROOT entry +- (this will happen if we switch from a device to a label) */ +- if (useRoot && !strncmp(*arg, "root=", 5)) { +- rootLine = getLineByType(LT_ROOT, entry->lines); +- if (rootLine) +- removeLine(entry, rootLine); ++ tmpl.indent = ""; ++ tmpl.type = type; ++ tmpl.numElements = 3; ++ tmpl.elements = ++ alloca(sizeof(*tmpl.elements) * tmpl.numElements); ++ tmpl.elements[0].item = kw->key; ++ tmpl.elements[0].indent = alloca(2); ++ sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); ++ tmpl.elements[1].item = (char *)val; ++ tmpl.elements[1].indent = alloca(2); ++ sprintf(tmpl.elements[1].indent, "%c", kw->nextChar); ++ tmpl.elements[2].item = alloca(strlen(lineend) + 1); ++ strcpy(tmpl.elements[2].item, lineend); ++ tmpl.elements[2].indent = ""; ++ } else { ++ kw = getKeywordByType(type, cfi); ++ if (!kw) { ++ fprintf(stderr, ++ "Looking up keyword for unknown type %d\n", ++ type); ++ abort(); + } +- } +- } +- +- free(usedElements); +- +- for (arg = oldArgs; *arg; arg++) { +- for (i = firstElement; i < line->numElements; i++) { +- if (multibootArgs && cfg->cfi->mbConcatArgs && +- !strcmp(line->elements[i].item, "--")) +- /* reached the end of hyper args, stop here */ +- break; +- if (!argMatch(line->elements[i].item, *arg)) { +- removeElement(line, i); +- break; ++ tmpl.type = type; ++ tmpl.numElements = val ? 2 : 1; ++ tmpl.elements = ++ alloca(sizeof(*tmpl.elements) * tmpl.numElements); ++ tmpl.elements[0].item = kw->key; ++ tmpl.elements[0].indent = alloca(2); ++ sprintf(tmpl.elements[0].indent, "%c", kw->nextChar); ++ if (val) { ++ tmpl.elements[1].item = (char *)val; ++ tmpl.elements[1].indent = ""; + } +- } +- /* handle removing LT_ROOT line too */ +- if (useRoot && !strncmp(*arg, "root=", 5)) { +- rootLine = getLineByType(LT_ROOT, entry->lines); +- if (rootLine) +- removeLine(entry, rootLine); +- } + } + +- if (line->numElements == 1) { +- /* don't need the line at all (note it has to be a +- LT_KERNELARGS for this to happen */ +- removeLine(entry, line); ++ /* The last non-empty line gives us the indention to us and the line ++ to insert after. Note that comments are considered empty lines, which ++ may not be ideal? If there are no lines or we are looking at the ++ first line, we use defaultIndent (the first line is normally indented ++ differently from the rest) */ ++ for (line = entry->lines, prev = NULL; line; line = line->next) { ++ if (line->numElements) ++ prev = line; ++ /* fall back on the last line if prev isn't otherwise set */ ++ if (!line->next && !prev) ++ prev = line; + } +- } + +- free(newArgs); +- free(oldArgs); ++ struct singleLine *menuEntry; ++ menuEntry = getLineByType(LT_MENUENTRY, entry->lines); ++ if (tmpl.type == LT_ENTRY_END) { ++ if (menuEntry) ++ tmpl.indent = menuEntry->indent; ++ else ++ tmpl.indent = defaultIndent ? : ""; ++ } else if (tmpl.type != LT_MENUENTRY) { ++ if (menuEntry) ++ tmpl.indent = "\t"; ++ else if (prev == entry->lines) ++ tmpl.indent = defaultIndent ? : ""; ++ else ++ tmpl.indent = prev->indent; ++ } + +- return 0; ++ return addLineTmpl(entry, &tmpl, prev, val, cfi); + } + +-int updateImage(struct grubConfig * cfg, const char * image, +- const char * prefix, const char * addArgs, +- const char * removeArgs, +- const char * addMBArgs, const char * removeMBArgs) { +- int rc = 0; ++void removeLine(struct singleEntry *entry, struct singleLine *line) ++{ ++ struct singleLine *prev; ++ int i; + +- if (!image) return rc; ++ for (i = 0; i < line->numElements; i++) { ++ free(line->elements[i].item); ++ free(line->elements[i].indent); ++ } ++ free(line->elements); ++ free(line->indent); + +- /* update the main args first... */ +- if (addArgs || removeArgs) +- rc = updateActualImage(cfg, image, prefix, addArgs, removeArgs, 0); +- if (rc) return rc; ++ if (line == entry->lines) { ++ entry->lines = line->next; ++ } else { ++ prev = entry->lines; ++ while (prev->next != line) ++ prev = prev->next; ++ prev->next = line->next; ++ } + +- /* and now any multiboot args */ +- if (addMBArgs || removeMBArgs) +- rc = updateActualImage(cfg, image, prefix, addMBArgs, removeMBArgs, 1); +- return rc; ++ free(line); + } + +-int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel, +- const char * image, const char * prefix, const char * initrd, +- const char * title) { +- struct singleEntry * entry; +- struct singleLine * line, * kernelLine, *endLine = NULL; +- int index = 0; +- +- if (!image) return 0; +- +- for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) { +- kernelLine = getLineByType(LT_MBMODULE, entry->lines); +- if (!kernelLine) continue; +- +- /* if title is supplied, the entry's title must match it. */ +- if (title) { +- char *linetitle; +- +- line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines); +- if (!line) +- continue; +- +- linetitle = extractTitle(cfg, line); +- if (!linetitle) +- continue; +- if (strcmp(title, linetitle)) { +- free(linetitle); +- continue; +- } +- free(linetitle); +- } +- +- if (prefix) { +- int prefixLen = strlen(prefix); +- if (!strncmp(initrd, prefix, prefixLen)) +- initrd += prefixLen; +- } +- endLine = getLineByType(LT_ENTRY_END, entry->lines); +- if (endLine) +- removeLine(entry, endLine); +- line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi), +- kernelLine->indent, initrd); +- if (!line) +- return 1; +- if (endLine) { +- line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); +- if (!line) +- return 1; +- } ++static void requote(struct singleLine *tmplLine, struct configFileInfo *cfi) ++{ ++ struct singleLine newLine = { ++ .indent = tmplLine->indent, ++ .type = tmplLine->type, ++ .next = tmplLine->next, ++ }; ++ int firstQuotedItem = -1; ++ int quoteLen = 0; ++ int j; ++ int element = 0; ++ char *c; ++ ++ c = malloc(strlen(tmplLine->elements[0].item) + 1); ++ strcpy(c, tmplLine->elements[0].item); ++ insertElement(&newLine, c, element++, cfi); ++ free(c); ++ c = NULL; ++ ++ for (j = 1; j < tmplLine->numElements; j++) { ++ if (firstQuotedItem == -1) { ++ quoteLen += strlen(tmplLine->elements[j].item); ++ ++ if (isquote(tmplLine->elements[j].item[0])) { ++ firstQuotedItem = j; ++ quoteLen += ++ strlen(tmplLine->elements[j].indent); ++ } else { ++ c = malloc(quoteLen + 1); ++ strcpy(c, tmplLine->elements[j].item); ++ insertElement(&newLine, c, element++, cfi); ++ free(c); ++ quoteLen = 0; ++ } ++ } else { ++ int itemlen = strlen(tmplLine->elements[j].item); ++ quoteLen += itemlen; ++ quoteLen += strlen(tmplLine->elements[j].indent); ++ ++ if (isquote(tmplLine->elements[j].item[itemlen - 1])) { ++ c = malloc(quoteLen + 1); ++ c[0] = '\0'; ++ for (int i = firstQuotedItem; i < j + 1; i++) { ++ strcat(c, tmplLine->elements[i].item); ++ strcat(c, tmplLine->elements[i].indent); ++ } ++ insertElement(&newLine, c, element++, cfi); ++ free(c); + +- break; +- } ++ firstQuotedItem = -1; ++ quoteLen = 0; ++ } ++ } ++ } ++ while (tmplLine->numElements) ++ removeElement(tmplLine, 0); ++ if (tmplLine->elements) ++ free(tmplLine->elements); + +- return 0; ++ tmplLine->numElements = newLine.numElements; ++ tmplLine->elements = newLine.elements; + } + +-int updateInitrd(struct grubConfig * cfg, const char * image, +- const char * prefix, const char * initrd, const char * title) { +- struct singleEntry * entry; +- struct singleLine * line, * kernelLine, *endLine = NULL; +- int index = 0; +- +- if (!image) return 0; +- +- for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { +- kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); +- if (!kernelLine) continue; +- +- /* if title is supplied, the entry's title must match it. */ +- if (title) { +- char *linetitle; +- +- line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines); +- if (!line) +- continue; +- +- linetitle = extractTitle(cfg, line); +- if (!linetitle) +- continue; +- if (strcmp(title, linetitle)) { +- free(linetitle); +- continue; +- } +- free(linetitle); +- } +- +- line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines); +- if (line) +- removeLine(entry, line); +- if (prefix) { +- int prefixLen = strlen(prefix); +- if (!strncmp(initrd, prefix, prefixLen)) +- initrd += prefixLen; +- } +- endLine = getLineByType(LT_ENTRY_END, entry->lines); +- if (endLine) +- removeLine(entry, endLine); +- enum lineType_e lt; +- switch(kernelLine->type) { +- case LT_KERNEL: +- lt = LT_INITRD; +- break; +- case LT_KERNEL_EFI: +- lt = LT_INITRD_EFI; +- break; +- case LT_KERNEL_16: +- lt = LT_INITRD_16; +- break; +- default: +- lt = preferredLineType(LT_INITRD, cfg->cfi); ++static void insertElement(struct singleLine *line, ++ const char *item, int insertHere, ++ struct configFileInfo *cfi) ++{ ++ struct keywordTypes *kw; ++ char indent[2] = ""; ++ ++ /* sanity check */ ++ if (insertHere > line->numElements) { ++ dbgPrintf ++ ("insertElement() adjusting insertHere from %d to %d\n", ++ insertHere, line->numElements); ++ insertHere = line->numElements; + } +- line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd); +- if (!line) +- return 1; +- if (endLine) { +- line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); +- if (!line) +- return 1; ++ ++ line->elements = realloc(line->elements, (line->numElements + 1) * ++ sizeof(*line->elements)); ++ memmove(&line->elements[insertHere + 1], ++ &line->elements[insertHere], ++ (line->numElements - insertHere) * sizeof(*line->elements)); ++ line->elements[insertHere].item = strdup(item); ++ ++ kw = getKeywordByType(line->type, cfi); ++ ++ if (line->numElements == 0) { ++ indent[0] = '\0'; ++ } else if (insertHere == 0) { ++ indent[0] = kw->nextChar; ++ } else if (kw->separatorChar != '\0') { ++ indent[0] = kw->separatorChar; ++ } else { ++ indent[0] = ' '; ++ } ++ ++ if (insertHere > 0 && line->elements[insertHere - 1].indent[0] == '\0') { ++ /* move the end-of-line forward */ ++ line->elements[insertHere].indent = ++ line->elements[insertHere - 1].indent; ++ line->elements[insertHere - 1].indent = strdup(indent); ++ } else { ++ line->elements[insertHere].indent = strdup(indent); + } + +- break; +- } ++ line->numElements++; + +- return 0; ++ dbgPrintf("insertElement(%s, '%s%s', %d)\n", ++ line->elements[0].item, ++ line->elements[insertHere].item, ++ line->elements[insertHere].indent, insertHere); + } + +-int checkDeviceBootloader(const char * device, const unsigned char * boot) { +- int fd; +- unsigned char bootSect[512]; +- int offset; ++static void removeElement(struct singleLine *line, int removeHere) ++{ ++ int i; + +- fd = open(device, O_RDONLY); +- if (fd < 0) { +- fprintf(stderr, _("grubby: unable to open %s: %s\n"), +- device, strerror(errno)); +- return 1; +- } ++ /* sanity check */ ++ if (removeHere >= line->numElements) ++ return; + +- if (read(fd, bootSect, 512) != 512) { +- fprintf(stderr, _("grubby: unable to read %s: %s\n"), +- device, strerror(errno)); +- return 1; +- } +- close(fd); ++ dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item, ++ removeHere, line->elements[removeHere].item); + +- /* first three bytes should match, a jmp short should be in there */ +- if (memcmp(boot, bootSect, 3)) +- return 0; ++ free(line->elements[removeHere].item); + +- if (boot[1] == JMP_SHORT_OPCODE) { +- offset = boot[2] + 2; +- } else if (boot[1] == 0xe8 || boot[1] == 0xe9) { +- offset = (boot[3] << 8) + boot[2] + 2; +- } else if (boot[0] == JMP_SHORT_OPCODE) { +- offset = boot[1] + 2; +- /* +- * it looks like grub, when copying stage1 into the mbr, patches stage1 +- * right after the JMP location, replacing other instructions such as +- * JMPs for NOOPs. So, relax the check a little bit by skipping those +- * different bytes. +- */ +- if ((bootSect[offset + 1] == NOOP_OPCODE) +- && (bootSect[offset + 2] == NOOP_OPCODE)) { +- offset = offset + 3; +- } +- } else if (boot[0] == 0xe8 || boot[0] == 0xe9) { +- offset = (boot[2] << 8) + boot[1] + 2; +- } else { +- return 0; +- } ++ if (removeHere > 1) { ++ /* previous argument gets this argument's post-indentation */ ++ free(line->elements[removeHere - 1].indent); ++ line->elements[removeHere - 1].indent = ++ line->elements[removeHere].indent; ++ } else { ++ free(line->elements[removeHere].indent); ++ } + +- if (memcmp(boot + offset, bootSect + offset, CODE_SEG_SIZE)) +- return 0; ++ /* now collapse the array, but don't bother to realloc smaller */ ++ for (i = removeHere; i < line->numElements - 1; i++) ++ line->elements[i] = line->elements[i + 1]; + +- return 2; ++ line->numElements--; + } + +-int checkLiloOnRaid(char * mdDev, const unsigned char * boot) { +- int fd; +- char buf[65536]; +- char * end; +- char * chptr; +- char * chptr2; +- int rc; +- +- /* it's on raid; we need to parse /proc/mdstat and check all of the +- *raw* devices listed in there */ ++int argMatch(const char *one, const char *two) ++{ ++ char *first, *second; ++ char *chptr; + +- if (!strncmp(mdDev, "/dev/", 5)) +- mdDev += 5; ++ first = strcpy(alloca(strlen(one) + 1), one); ++ second = strcpy(alloca(strlen(two) + 1), two); + +- if ((fd = open("/proc/mdstat", O_RDONLY)) < 0) { +- fprintf(stderr, _("grubby: failed to open /proc/mdstat: %s\n"), +- strerror(errno)); +- return 2; +- } ++ chptr = strchr(first, '='); ++ if (chptr) ++ *chptr = '\0'; + +- rc = read(fd, buf, sizeof(buf) - 1); +- if (rc < 0 || rc == (sizeof(buf) - 1)) { +- fprintf(stderr, _("grubby: failed to read /proc/mdstat: %s\n"), +- strerror(errno)); +- close(fd); +- return 2; +- } +- close(fd); +- buf[rc] = '\0'; +- +- chptr = buf; +- while (*chptr) { +- end = strchr(chptr, '\n'); +- if (!end) break; +- *end = '\0'; ++ chptr = strchr(second, '='); ++ if (chptr) ++ *chptr = '\0'; + +- if (!strncmp(chptr, mdDev, strlen(mdDev)) && +- chptr[strlen(mdDev)] == ' ') { +- +- /* found the device */ +- while (*chptr && *chptr != ':') chptr++; +- chptr++; +- while (*chptr && isspace(*chptr)) chptr++; +- +- /* skip the "active" bit */ +- while (*chptr && !isspace(*chptr)) chptr++; +- while (*chptr && isspace(*chptr)) chptr++; +- +- /* skip the raid level */ +- while (*chptr && !isspace(*chptr)) chptr++; +- while (*chptr && isspace(*chptr)) chptr++; +- +- /* everything else is partition stuff */ +- while (*chptr) { +- chptr2 = chptr; +- while (*chptr2 && *chptr2 != '[') chptr2++; +- if (!*chptr2) break; +- +- /* yank off the numbers at the end */ +- chptr2--; +- while (isdigit(*chptr2) && chptr2 > chptr) chptr2--; +- chptr2++; +- *chptr2 = '\0'; +- +- /* Better, now we need the /dev/ back. We're done with +- * everything before this point, so we can just put +- * the /dev/ part there. There will always be room. */ +- memcpy(chptr - 5, "/dev/", 5); +- rc = checkDeviceBootloader(chptr - 5, boot); +- if (rc != 2) { +- return rc; +- } ++ return strcmp(first, second); ++} + +- chptr = chptr2 + 1; +- /* skip the [11] bit */ +- while (*chptr && !isspace(*chptr)) chptr++; +- /* and move to the next one */ +- while (*chptr && isspace(*chptr)) chptr++; +- } ++int updateActualImage(struct grubConfig *cfg, const char *image, ++ const char *prefix, const char *addArgs, ++ const char *removeArgs, int multibootArgs) ++{ ++ struct singleEntry *entry; ++ struct singleLine *line, *rootLine; ++ int index = 0; ++ int i, k; ++ const char **newArgs, **oldArgs; ++ const char **arg; ++ int useKernelArgs, useRoot; ++ int firstElement; ++ int *usedElements; ++ int doreplace; ++ ++ if (!image) ++ return 0; + +- /* we're good to go */ +- return 2; ++ if (!addArgs) { ++ newArgs = malloc(sizeof(*newArgs)); ++ *newArgs = NULL; ++ } else { ++ if (poptParseArgvString(addArgs, NULL, &newArgs)) { ++ fprintf(stderr, ++ _("grubby: error separating arguments '%s'\n"), ++ addArgs); ++ return 1; ++ } + } + +- chptr = end + 1; +- } ++ if (!removeArgs) { ++ oldArgs = malloc(sizeof(*oldArgs)); ++ *oldArgs = NULL; ++ } else { ++ if (poptParseArgvString(removeArgs, NULL, &oldArgs)) { ++ fprintf(stderr, ++ _("grubby: error separating arguments '%s'\n"), ++ removeArgs); ++ free(newArgs); ++ return 1; ++ } ++ } + +- fprintf(stderr, +- _("grubby: raid device /dev/%s not found in /proc/mdstat\n"), +- mdDev); +- return 0; +-} ++ useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi) ++ && (!multibootArgs || cfg->cfi->mbConcatArgs)); + +-int checkForLilo(struct grubConfig * config) { +- int fd; +- unsigned char boot[512]; +- struct singleLine * line; ++ useRoot = (getKeywordByType(LT_ROOT, cfg->cfi) ++ && !multibootArgs); + +- for (line = config->theLines; line; line = line->next) +- if (line->type == LT_BOOT) break; ++ for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { + +- if (!line) { +- fprintf(stderr, +- _("grubby: no boot line found in lilo configuration\n")); +- return 1; +- } ++ if (multibootArgs && !entry->multiboot) ++ continue; + +- if (line->numElements != 2) return 1; ++ /* Determine where to put the args. If this config supports ++ * LT_KERNELARGS, use that. Otherwise use ++ * LT_HYPER/LT_KERNEL/LT_MBMODULE lines. ++ */ ++ if (useKernelArgs) { ++ line = getLineByType(LT_KERNELARGS, entry->lines); ++ if (!line) { ++ /* no LT_KERNELARGS, need to add it */ ++ line = addLine(entry, cfg->cfi, LT_KERNELARGS, ++ cfg->secondaryIndent, NULL); ++ } ++ firstElement = 1; + +- fd = open("/boot/boot.b", O_RDONLY); +- if (fd < 0) { +- fprintf(stderr, _("grubby: unable to open %s: %s\n"), +- "/boot/boot.b", strerror(errno)); +- return 1; +- } ++ } else if (multibootArgs) { ++ line = getLineByType(LT_HYPER, entry->lines); ++ if (!line) { ++ /* a multiboot entry without LT_HYPER? */ ++ continue; ++ } ++ firstElement = 2; + +- if (read(fd, boot, 512) != 512) { +- fprintf(stderr, _("grubby: unable to read %s: %s\n"), +- "/boot/boot.b", strerror(errno)); +- return 1; +- } +- close(fd); ++ } else { ++ line = ++ getLineByType(LT_KERNEL | LT_MBMODULE | ++ LT_KERNEL_EFI | LT_KERNEL_16, ++ entry->lines); ++ if (!line) { ++ /* no LT_KERNEL or LT_MBMODULE in this entry? */ ++ continue; ++ } ++ firstElement = 2; ++ } + +- if (!strncmp("/dev/md", line->elements[1].item, 7)) +- return checkLiloOnRaid(line->elements[1].item, boot); ++ /* handle the elilo case which does: ++ * append="hypervisor args -- kernel args" ++ */ ++ if (entry->multiboot && cfg->cfi->mbConcatArgs) { ++ /* this is a multiboot entry, make sure there's ++ * -- on the args line ++ */ ++ for (i = firstElement; i < line->numElements; i++) { ++ if (!strcmp(line->elements[i].item, "--")) ++ break; ++ } ++ if (i == line->numElements) { ++ /* assume all existing args are kernel args, ++ * prepend -- to make it official ++ */ ++ insertElement(line, "--", firstElement, ++ cfg->cfi); ++ i = firstElement; ++ } ++ if (!multibootArgs) { ++ /* kernel args start after the -- */ ++ firstElement = i + 1; ++ } ++ } else if (cfg->cfi->mbConcatArgs) { ++ /* this is a non-multiboot entry, remove hyper args */ ++ for (i = firstElement; i < line->numElements; i++) { ++ if (!strcmp(line->elements[i].item, "--")) ++ break; ++ } ++ if (i < line->numElements) { ++ /* remove args up to -- */ ++ while (strcmp ++ (line->elements[firstElement].item, ++ "--")) ++ removeElement(line, firstElement); ++ /* remove -- */ ++ removeElement(line, firstElement); ++ } ++ } + +- return checkDeviceBootloader(line->elements[1].item, boot); +-} ++ usedElements = calloc(line->numElements, sizeof(*usedElements)); + +-int checkForGrub2(struct grubConfig * config) { +- if (!access("/etc/grub.d/", R_OK)) +- return 2; ++ for (k = 0, arg = newArgs; *arg; arg++, k++) { + +- return 1; +-} ++ doreplace = 1; ++ for (i = firstElement; i < line->numElements; i++) { ++ if (multibootArgs && cfg->cfi->mbConcatArgs && ++ !strcmp(line->elements[i].item, "--")) { ++ /* reached the end of hyper args, insert here */ ++ doreplace = 0; ++ break; ++ } ++ if (usedElements[i]) ++ continue; ++ if (!argMatch(line->elements[i].item, *arg)) { ++ usedElements[i] = 1; ++ break; ++ } ++ } + +-int checkForGrub(struct grubConfig * config) { +- int fd; +- unsigned char bootSect[512]; +- char * boot; +- int onSuse = isSuseSystem(); ++ if (i < line->numElements && doreplace) { ++ /* direct replacement */ ++ free(line->elements[i].item); ++ line->elements[i].item = strdup(*arg); ++ ++ } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) { ++ /* root= replacement */ ++ rootLine = getLineByType(LT_ROOT, entry->lines); ++ if (rootLine) { ++ free(rootLine->elements[1].item); ++ rootLine->elements[1].item = ++ strdup(*arg + 5); ++ } else { ++ rootLine = ++ addLine(entry, cfg->cfi, LT_ROOT, ++ cfg->secondaryIndent, ++ *arg + 5); ++ } ++ } + ++ else { ++ /* insert/append */ ++ insertElement(line, *arg, i, cfg->cfi); ++ usedElements = ++ realloc(usedElements, ++ line->numElements * ++ sizeof(*usedElements)); ++ memmove(&usedElements[i + 1], &usedElements[i], ++ line->numElements - i - 1); ++ usedElements[i] = 1; ++ ++ /* if we updated a root= here even though there is a ++ LT_ROOT available we need to remove the LT_ROOT entry ++ (this will happen if we switch from a device to a label) */ ++ if (useRoot && !strncmp(*arg, "root=", 5)) { ++ rootLine = ++ getLineByType(LT_ROOT, ++ entry->lines); ++ if (rootLine) ++ removeLine(entry, rootLine); ++ } ++ } ++ } + +- if (onSuse) { +- if (parseSuseGrubConf(NULL, &boot)) +- return 0; +- } else { +- if (parseSysconfigGrub(NULL, &boot)) +- return 0; +- } ++ free(usedElements); + +- /* assume grub is not installed -- not an error condition */ +- if (!boot) +- return 0; ++ for (arg = oldArgs; *arg; arg++) { ++ for (i = firstElement; i < line->numElements; i++) { ++ if (multibootArgs && cfg->cfi->mbConcatArgs && ++ !strcmp(line->elements[i].item, "--")) ++ /* reached the end of hyper args, stop here */ ++ break; ++ if (!argMatch(line->elements[i].item, *arg)) { ++ removeElement(line, i); ++ break; ++ } ++ } ++ /* handle removing LT_ROOT line too */ ++ if (useRoot && !strncmp(*arg, "root=", 5)) { ++ rootLine = getLineByType(LT_ROOT, entry->lines); ++ if (rootLine) ++ removeLine(entry, rootLine); ++ } ++ } + +- fd = open("/boot/grub/stage1", O_RDONLY); +- if (fd < 0) +- /* this doesn't exist if grub hasn't been installed */ +- return 0; ++ if (line->numElements == 1) { ++ /* don't need the line at all (note it has to be a ++ LT_KERNELARGS for this to happen */ ++ removeLine(entry, line); ++ } ++ } + +- if (read(fd, bootSect, 512) != 512) { +- fprintf(stderr, _("grubby: unable to read %s: %s\n"), +- "/boot/grub/stage1", strerror(errno)); +- close(fd); +- return 1; +- } +- close(fd); ++ free(newArgs); ++ free(oldArgs); + +- /* The more elaborate checks do not work on SuSE. The checks done +- * seem to be reasonble (at least for now), so just return success +- */ +- if (onSuse) +- return 2; ++ return 0; ++} + +- return checkDeviceBootloader(boot, bootSect); ++int updateImage(struct grubConfig *cfg, const char *image, ++ const char *prefix, const char *addArgs, ++ const char *removeArgs, ++ const char *addMBArgs, const char *removeMBArgs) ++{ ++ int rc = 0; ++ ++ if (!image) ++ return rc; ++ ++ /* update the main args first... */ ++ if (addArgs || removeArgs) ++ rc = updateActualImage(cfg, image, prefix, addArgs, removeArgs, ++ 0); ++ if (rc) ++ return rc; ++ ++ /* and now any multiboot args */ ++ if (addMBArgs || removeMBArgs) ++ rc = updateActualImage(cfg, image, prefix, addMBArgs, ++ removeMBArgs, 1); ++ return rc; + } + +-int checkForExtLinux(struct grubConfig * config) { +- int fd; +- unsigned char bootSect[512]; +- char * boot; +- char executable[] = "/boot/extlinux/extlinux"; ++int addMBInitrd(struct grubConfig *cfg, const char *newMBKernel, ++ const char *image, const char *prefix, const char *initrd, ++ const char *title) ++{ ++ struct singleEntry *entry; ++ struct singleLine *line, *kernelLine, *endLine = NULL; ++ int index = 0; + +- printf("entered: checkForExtLinux()\n"); ++ if (!image) ++ return 0; + +- if (parseSysconfigGrub(NULL, &boot)) +- return 0; ++ for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); ++ index++) { ++ kernelLine = getLineByType(LT_MBMODULE, entry->lines); ++ if (!kernelLine) ++ continue; + +- /* assume grub is not installed -- not an error condition */ +- if (!boot) +- return 0; ++ /* if title is supplied, the entry's title must match it. */ ++ if (title) { ++ char *linetitle; ++ ++ line = ++ getLineByType(LT_TITLE | LT_MENUENTRY, ++ entry->lines); ++ if (!line) ++ continue; ++ ++ linetitle = extractTitle(cfg, line); ++ if (!linetitle) ++ continue; ++ if (strcmp(title, linetitle)) { ++ free(linetitle); ++ continue; ++ } ++ free(linetitle); ++ } + +- fd = open(executable, O_RDONLY); +- if (fd < 0) +- /* this doesn't exist if grub hasn't been installed */ +- return 0; ++ if (prefix) { ++ int prefixLen = strlen(prefix); ++ if (!strncmp(initrd, prefix, prefixLen)) ++ initrd += prefixLen; ++ } ++ endLine = getLineByType(LT_ENTRY_END, entry->lines); ++ if (endLine) ++ removeLine(entry, endLine); ++ line = ++ addLine(entry, cfg->cfi, ++ preferredLineType(LT_MBMODULE, cfg->cfi), ++ kernelLine->indent, initrd); ++ if (!line) ++ return 1; ++ if (endLine) { ++ line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); ++ if (!line) ++ return 1; ++ } + +- if (read(fd, bootSect, 512) != 512) { +- fprintf(stderr, _("grubby: unable to read %s: %s\n"), +- executable, strerror(errno)); +- return 1; +- } +- close(fd); ++ break; ++ } + +- return checkDeviceBootloader(boot, bootSect); ++ return 0; + } + +-int checkForYaboot(struct grubConfig * config) { +- /* +- * This is a simplistic check that we consider good enough for own puporses +- * +- * If we were to properly check if yaboot is *installed* we'd need to: +- * 1) get the system boot device (LT_BOOT) +- * 2) considering it's a raw filesystem, check if the yaboot binary matches +- * the content on the boot device +- * 3) if not, copy the binary to a temporary file and run "addnote" on it +- * 4) check again if binary and boot device contents match +- */ +- if (!access("/etc/yaboot.conf", R_OK)) +- return 2; +- +- return 1; +-} ++int updateInitrd(struct grubConfig *cfg, const char *image, ++ const char *prefix, const char *initrd, const char *title) ++{ ++ struct singleEntry *entry; ++ struct singleLine *line, *kernelLine, *endLine = NULL; ++ int index = 0; + +-int checkForElilo(struct grubConfig * config) { +- if (!access("/etc/elilo.conf", R_OK)) +- return 2; ++ if (!image) ++ return 0; + +- return 1; +-} ++ for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { ++ kernelLine = ++ getLineByType(LT_KERNEL | LT_KERNEL_EFI | LT_KERNEL_16, ++ entry->lines); ++ if (!kernelLine) ++ continue; + +-static char * getRootSpecifier(char * str) { +- char * idx, * rootspec = NULL; ++ /* if title is supplied, the entry's title must match it. */ ++ if (title) { ++ char *linetitle; ++ ++ line = ++ getLineByType(LT_TITLE | LT_MENUENTRY, ++ entry->lines); ++ if (!line) ++ continue; ++ ++ linetitle = extractTitle(cfg, line); ++ if (!linetitle) ++ continue; ++ if (strcmp(title, linetitle)) { ++ free(linetitle); ++ continue; ++ } ++ free(linetitle); ++ } + +- if (*str == '(') { +- idx = rootspec = strdup(str); +- while(*idx && (*idx != ')') && (!isspace(*idx))) idx++; +- *(++idx) = '\0'; +- } +- return rootspec; ++ line = ++ getLineByType(LT_INITRD | LT_INITRD_EFI | LT_INITRD_16, ++ entry->lines); ++ if (line) ++ removeLine(entry, line); ++ if (prefix) { ++ int prefixLen = strlen(prefix); ++ if (!strncmp(initrd, prefix, prefixLen)) ++ initrd += prefixLen; ++ } ++ endLine = getLineByType(LT_ENTRY_END, entry->lines); ++ if (endLine) ++ removeLine(entry, endLine); ++ enum lineType_e lt; ++ switch (kernelLine->type) { ++ case LT_KERNEL: ++ lt = LT_INITRD; ++ break; ++ case LT_KERNEL_EFI: ++ lt = LT_INITRD_EFI; ++ break; ++ case LT_KERNEL_16: ++ lt = LT_INITRD_16; ++ break; ++ default: ++ lt = preferredLineType(LT_INITRD, cfg->cfi); ++ } ++ line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd); ++ if (!line) ++ return 1; ++ if (endLine) { ++ line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL); ++ if (!line) ++ return 1; ++ } ++ ++ break; ++ } ++ ++ return 0; + } + +-static char * getInitrdVal(struct grubConfig * config, +- const char * prefix, struct singleLine *tmplLine, +- const char * newKernelInitrd, +- const char ** extraInitrds, int extraInitrdCount) ++int checkDeviceBootloader(const char *device, const unsigned char *boot) + { +- char *initrdVal, *end; +- int i; +- size_t totalSize; +- size_t prefixLen; +- char separatorChar; ++ int fd; ++ unsigned char bootSect[512]; ++ int offset; ++ ++ fd = open(device, O_RDONLY); ++ if (fd < 0) { ++ fprintf(stderr, _("grubby: unable to open %s: %s\n"), ++ device, strerror(errno)); ++ return 1; ++ } + +- prefixLen = strlen(prefix); +- totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */; ++ if (read(fd, bootSect, 512) != 512) { ++ fprintf(stderr, _("grubby: unable to read %s: %s\n"), ++ device, strerror(errno)); ++ return 1; ++ } ++ close(fd); + +- for (i = 0; i < extraInitrdCount; i++) { +- totalSize += sizeof(separatorChar); +- totalSize += strlen(extraInitrds[i]) - prefixLen; +- } ++ /* first three bytes should match, a jmp short should be in there */ ++ if (memcmp(boot, bootSect, 3)) ++ return 0; + +- initrdVal = end = malloc(totalSize); ++ if (boot[1] == JMP_SHORT_OPCODE) { ++ offset = boot[2] + 2; ++ } else if (boot[1] == 0xe8 || boot[1] == 0xe9) { ++ offset = (boot[3] << 8) + boot[2] + 2; ++ } else if (boot[0] == JMP_SHORT_OPCODE) { ++ offset = boot[1] + 2; ++ /* ++ * it looks like grub, when copying stage1 into the mbr, patches stage1 ++ * right after the JMP location, replacing other instructions such as ++ * JMPs for NOOPs. So, relax the check a little bit by skipping those ++ * different bytes. ++ */ ++ if ((bootSect[offset + 1] == NOOP_OPCODE) ++ && (bootSect[offset + 2] == NOOP_OPCODE)) { ++ offset = offset + 3; ++ } ++ } else if (boot[0] == 0xe8 || boot[0] == 0xe9) { ++ offset = (boot[2] << 8) + boot[1] + 2; ++ } else { ++ return 0; ++ } + +- end = stpcpy (end, newKernelInitrd + prefixLen); ++ if (memcmp(boot + offset, bootSect + offset, CODE_SEG_SIZE)) ++ return 0; + +- separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar; +- for (i = 0; i < extraInitrdCount; i++) { +- const char *extraInitrd; +- int j; ++ return 2; ++} + +- extraInitrd = extraInitrds[i] + prefixLen; +- /* Don't add entries that are already there */ +- if (tmplLine != NULL) { +- for (j = 2; j < tmplLine->numElements; j++) +- if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0) +- break; ++int checkLiloOnRaid(char *mdDev, const unsigned char *boot) ++{ ++ int fd; ++ char buf[65536]; ++ char *end; ++ char *chptr; ++ char *chptr2; ++ int rc; ++ ++ /* it's on raid; we need to parse /proc/mdstat and check all of the ++ *raw* devices listed in there */ ++ ++ if (!strncmp(mdDev, "/dev/", 5)) ++ mdDev += 5; ++ ++ if ((fd = open("/proc/mdstat", O_RDONLY)) < 0) { ++ fprintf(stderr, _("grubby: failed to open /proc/mdstat: %s\n"), ++ strerror(errno)); ++ return 2; ++ } + +- if (j != tmplLine->numElements) +- continue; ++ rc = read(fd, buf, sizeof(buf) - 1); ++ if (rc < 0 || rc == (sizeof(buf) - 1)) { ++ fprintf(stderr, _("grubby: failed to read /proc/mdstat: %s\n"), ++ strerror(errno)); ++ close(fd); ++ return 2; + } ++ close(fd); ++ buf[rc] = '\0'; + +- *end++ = separatorChar; +- end = stpcpy(end, extraInitrd); +- } ++ chptr = buf; ++ while (*chptr) { ++ end = strchr(chptr, '\n'); ++ if (!end) ++ break; ++ *end = '\0'; ++ ++ if (!strncmp(chptr, mdDev, strlen(mdDev)) && ++ chptr[strlen(mdDev)] == ' ') { ++ ++ /* found the device */ ++ while (*chptr && *chptr != ':') ++ chptr++; ++ chptr++; ++ while (*chptr && isspace(*chptr)) ++ chptr++; ++ ++ /* skip the "active" bit */ ++ while (*chptr && !isspace(*chptr)) ++ chptr++; ++ while (*chptr && isspace(*chptr)) ++ chptr++; ++ ++ /* skip the raid level */ ++ while (*chptr && !isspace(*chptr)) ++ chptr++; ++ while (*chptr && isspace(*chptr)) ++ chptr++; ++ ++ /* everything else is partition stuff */ ++ while (*chptr) { ++ chptr2 = chptr; ++ while (*chptr2 && *chptr2 != '[') ++ chptr2++; ++ if (!*chptr2) ++ break; + +- return initrdVal; +-} ++ /* yank off the numbers at the end */ ++ chptr2--; ++ while (isdigit(*chptr2) && chptr2 > chptr) ++ chptr2--; ++ chptr2++; ++ *chptr2 = '\0'; ++ ++ /* Better, now we need the /dev/ back. We're done with ++ * everything before this point, so we can just put ++ * the /dev/ part there. There will always be room. */ ++ memcpy(chptr - 5, "/dev/", 5); ++ rc = checkDeviceBootloader(chptr - 5, boot); ++ if (rc != 2) { ++ return rc; ++ } + +-int addNewKernel(struct grubConfig * config, struct singleEntry * template, +- const char * prefix, +- const char * newKernelPath, const char * newKernelTitle, +- const char * newKernelArgs, const char * newKernelInitrd, +- const char ** extraInitrds, int extraInitrdCount, +- const char * newMBKernel, const char * newMBKernelArgs) { +- struct singleEntry * new; +- struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL; +- int needs; +- char * chptr; +- +- if (!newKernelPath) return 0; +- +- /* if the newKernelTitle is too long silently munge it into something +- * we can live with. truncating is first check, then we'll just mess with +- * it until it looks better */ +- if (config->cfi->maxTitleLength && +- (strlen(newKernelTitle) > config->cfi->maxTitleLength)) { +- char * buf = alloca(config->cfi->maxTitleLength + 7); +- char * numBuf = alloca(config->cfi->maxTitleLength + 1); +- int i = 1; +- +- sprintf(buf, "TITLE=%.*s", config->cfi->maxTitleLength, newKernelTitle); +- while (findEntryByPath(config, buf, NULL, NULL)) { +- sprintf(numBuf, "%d", i++); +- strcpy(buf + strlen(buf) - strlen(numBuf), numBuf); +- } +- +- newKernelTitle = buf + 6; +- } +- +- new = malloc(sizeof(*new)); +- new->skip = 0; +- new->multiboot = 0; +- new->next = config->entries; +- new->lines = NULL; +- config->entries = new; +- +- /* copy/update from the template */ +- needs = NEED_KERNEL | NEED_TITLE; +- if (newKernelInitrd) +- needs |= NEED_INITRD; +- if (newMBKernel) { +- needs |= NEED_MB; +- new->multiboot = 1; +- } +- +- if (template) { +- for (masterLine = template->lines; +- masterLine && (tmplLine = lineDup(masterLine)); +- lineFree(tmplLine), masterLine = masterLine->next) +- { +- dbgPrintf("addNewKernel processing %d\n", tmplLine->type); +- +- /* skip comments */ +- chptr = tmplLine->indent; +- while (*chptr && isspace(*chptr)) chptr++; +- if (*chptr == '#') continue; +- +- if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) { +- if (!template->multiboot && (needs & NEED_MB)) { +- /* it's not a multiboot template and this is the kernel +- * line. Try to be intelligent about inserting the +- * hypervisor at the same time. +- */ +- if (config->cfi->mbHyperFirst) { +- /* insert the hypervisor first */ +- newLine = addLine(new, config->cfi, LT_HYPER, +- tmplLine->indent, +- newMBKernel + strlen(prefix)); +- /* set up for adding the kernel line */ +- free(tmplLine->indent); +- tmplLine->indent = strdup(config->secondaryIndent); +- needs &= ~NEED_MB; +- } +- if (needs & NEED_KERNEL) { +- /* use addLineTmpl to preserve line elements, +- * otherwise we could just call addLine. Unfortunately +- * this means making some changes to the template +- * such as the indent change above and the type +- * change below. +- */ +- struct keywordTypes * mbm_kw = +- getKeywordByType(LT_MBMODULE, config->cfi); +- if (mbm_kw) { +- tmplLine->type = LT_MBMODULE; +- free(tmplLine->elements[0].item); +- tmplLine->elements[0].item = strdup(mbm_kw->key); ++ chptr = chptr2 + 1; ++ /* skip the [11] bit */ ++ while (*chptr && !isspace(*chptr)) ++ chptr++; ++ /* and move to the next one */ ++ while (*chptr && isspace(*chptr)) ++ chptr++; + } +- newLine = addLineTmpl(new, tmplLine, newLine, +- newKernelPath + strlen(prefix), config->cfi); +- needs &= ~NEED_KERNEL; +- } +- if (needs & NEED_MB) { /* !mbHyperFirst */ +- newLine = addLine(new, config->cfi, LT_HYPER, +- config->secondaryIndent, +- newMBKernel + strlen(prefix)); +- needs &= ~NEED_MB; +- } +- } else if (needs & NEED_KERNEL) { +- newLine = addLineTmpl(new, tmplLine, newLine, +- newKernelPath + strlen(prefix), config->cfi); +- needs &= ~NEED_KERNEL; +- } + +- } else if (tmplLine->type == LT_HYPER && +- tmplLine->numElements >= 2) { +- if (needs & NEED_MB) { +- newLine = addLineTmpl(new, tmplLine, newLine, +- newMBKernel + strlen(prefix), config->cfi); +- needs &= ~NEED_MB; ++ /* we're good to go */ ++ return 2; + } + +- } else if (tmplLine->type == LT_MBMODULE && +- tmplLine->numElements >= 2) { +- if (new->multiboot) { +- if (needs & NEED_KERNEL) { +- newLine = addLineTmpl(new, tmplLine, newLine, +- newKernelPath + +- strlen(prefix), config->cfi); +- needs &= ~NEED_KERNEL; +- } else if (config->cfi->mbInitRdIsModule && +- (needs & NEED_INITRD)) { +- char *initrdVal; +- initrdVal = getInitrdVal(config, prefix, tmplLine, +- newKernelInitrd, extraInitrds, +- extraInitrdCount); +- newLine = addLineTmpl(new, tmplLine, newLine, +- initrdVal, config->cfi); +- free(initrdVal); +- needs &= ~NEED_INITRD; +- } +- } else if (needs & NEED_KERNEL) { +- /* template is multi but new is not, +- * insert the kernel in the first module slot +- */ +- tmplLine->type = preferredLineType(LT_KERNEL, config->cfi); +- free(tmplLine->elements[0].item); +- tmplLine->elements[0].item = +- strdup(getKeywordByType(tmplLine->type, +- config->cfi)->key); +- newLine = addLineTmpl(new, tmplLine, newLine, +- newKernelPath + strlen(prefix), +- config->cfi); +- needs &= ~NEED_KERNEL; +- } else if (needs & NEED_INITRD) { +- char *initrdVal; +- /* template is multi but new is not, +- * insert the initrd in the second module slot +- */ +- tmplLine->type = preferredLineType(LT_INITRD, config->cfi); +- free(tmplLine->elements[0].item); +- tmplLine->elements[0].item = +- strdup(getKeywordByType(tmplLine->type, +- config->cfi)->key); +- initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount); +- newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi); +- free(initrdVal); +- needs &= ~NEED_INITRD; +- } ++ chptr = end + 1; ++ } ++ ++ fprintf(stderr, ++ _("grubby: raid device /dev/%s not found in /proc/mdstat\n"), ++ mdDev); ++ return 0; ++} ++ ++int checkForLilo(struct grubConfig *config) ++{ ++ int fd; ++ unsigned char boot[512]; ++ struct singleLine *line; ++ ++ for (line = config->theLines; line; line = line->next) ++ if (line->type == LT_BOOT) ++ break; ++ ++ if (!line) { ++ fprintf(stderr, ++ _ ++ ("grubby: no boot line found in lilo configuration\n")); ++ return 1; ++ } ++ ++ if (line->numElements != 2) ++ return 1; ++ ++ fd = open("/boot/boot.b", O_RDONLY); ++ if (fd < 0) { ++ fprintf(stderr, _("grubby: unable to open %s: %s\n"), ++ "/boot/boot.b", strerror(errno)); ++ return 1; ++ } ++ ++ if (read(fd, boot, 512) != 512) { ++ fprintf(stderr, _("grubby: unable to read %s: %s\n"), ++ "/boot/boot.b", strerror(errno)); ++ return 1; ++ } ++ close(fd); ++ ++ if (!strncmp("/dev/md", line->elements[1].item, 7)) ++ return checkLiloOnRaid(line->elements[1].item, boot); ++ ++ return checkDeviceBootloader(line->elements[1].item, boot); ++} ++ ++int checkForGrub2(struct grubConfig *config) ++{ ++ if (!access("/etc/grub.d/", R_OK)) ++ return 2; ++ ++ return 1; ++} ++ ++int checkForGrub(struct grubConfig *config) ++{ ++ int fd; ++ unsigned char bootSect[512]; ++ char *boot; ++ int onSuse = isSuseSystem(); ++ ++ if (onSuse) { ++ if (parseSuseGrubConf(NULL, &boot)) ++ return 0; ++ } else { ++ if (parseSysconfigGrub(NULL, &boot)) ++ return 0; ++ } ++ ++ /* assume grub is not installed -- not an error condition */ ++ if (!boot) ++ return 0; + +- } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) { +- if (needs & NEED_INITRD && +- new->multiboot && !template->multiboot && +- config->cfi->mbInitRdIsModule) { +- /* make sure we don't insert the module initrd +- * before the module kernel... if we don't do it here, +- * it will be inserted following the template. +- */ +- if (!needs & NEED_KERNEL) { +- char *initrdVal; +- +- initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount); +- newLine = addLine(new, config->cfi, LT_MBMODULE, +- config->secondaryIndent, +- initrdVal); +- free(initrdVal); +- needs &= ~NEED_INITRD; +- } +- } else if (needs & NEED_INITRD) { +- char *initrdVal; +- initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount); +- newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi); +- free(initrdVal); +- needs &= ~NEED_INITRD; ++ fd = open("/boot/grub/stage1", O_RDONLY); ++ if (fd < 0) ++ /* this doesn't exist if grub hasn't been installed */ ++ return 0; ++ ++ if (read(fd, bootSect, 512) != 512) { ++ fprintf(stderr, _("grubby: unable to read %s: %s\n"), ++ "/boot/grub/stage1", strerror(errno)); ++ close(fd); ++ return 1; ++ } ++ close(fd); ++ ++ /* The more elaborate checks do not work on SuSE. The checks done ++ * seem to be reasonble (at least for now), so just return success ++ */ ++ if (onSuse) ++ return 2; ++ ++ return checkDeviceBootloader(boot, bootSect); ++} ++ ++int checkForExtLinux(struct grubConfig *config) ++{ ++ int fd; ++ unsigned char bootSect[512]; ++ char *boot; ++ char executable[] = "/boot/extlinux/extlinux"; ++ ++ printf("entered: checkForExtLinux()\n"); ++ ++ if (parseSysconfigGrub(NULL, &boot)) ++ return 0; ++ ++ /* assume grub is not installed -- not an error condition */ ++ if (!boot) ++ return 0; ++ ++ fd = open(executable, O_RDONLY); ++ if (fd < 0) ++ /* this doesn't exist if grub hasn't been installed */ ++ return 0; ++ ++ if (read(fd, bootSect, 512) != 512) { ++ fprintf(stderr, _("grubby: unable to read %s: %s\n"), ++ executable, strerror(errno)); ++ return 1; ++ } ++ close(fd); ++ ++ return checkDeviceBootloader(boot, bootSect); ++} ++ ++int checkForYaboot(struct grubConfig *config) ++{ ++ /* ++ * This is a simplistic check that we consider good enough for own puporses ++ * ++ * If we were to properly check if yaboot is *installed* we'd need to: ++ * 1) get the system boot device (LT_BOOT) ++ * 2) considering it's a raw filesystem, check if the yaboot binary matches ++ * the content on the boot device ++ * 3) if not, copy the binary to a temporary file and run "addnote" on it ++ * 4) check again if binary and boot device contents match ++ */ ++ if (!access("/etc/yaboot.conf", R_OK)) ++ return 2; ++ ++ return 1; ++} ++ ++int checkForElilo(struct grubConfig *config) ++{ ++ if (!access("/etc/elilo.conf", R_OK)) ++ return 2; ++ ++ return 1; ++} ++ ++static char *getRootSpecifier(char *str) ++{ ++ char *idx, *rootspec = NULL; ++ ++ if (*str == '(') { ++ idx = rootspec = strdup(str); ++ while (*idx && (*idx != ')') && (!isspace(*idx))) ++ idx++; ++ *(++idx) = '\0'; ++ } ++ return rootspec; ++} ++ ++static char *getInitrdVal(struct grubConfig *config, ++ const char *prefix, struct singleLine *tmplLine, ++ const char *newKernelInitrd, ++ const char **extraInitrds, int extraInitrdCount) ++{ ++ char *initrdVal, *end; ++ int i; ++ size_t totalSize; ++ size_t prefixLen; ++ char separatorChar; ++ ++ prefixLen = strlen(prefix); ++ totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */ ; ++ ++ for (i = 0; i < extraInitrdCount; i++) { ++ totalSize += sizeof(separatorChar); ++ totalSize += strlen(extraInitrds[i]) - prefixLen; ++ } ++ ++ initrdVal = end = malloc(totalSize); ++ ++ end = stpcpy(end, newKernelInitrd + prefixLen); ++ ++ separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar; ++ for (i = 0; i < extraInitrdCount; i++) { ++ const char *extraInitrd; ++ int j; ++ ++ extraInitrd = extraInitrds[i] + prefixLen; ++ /* Don't add entries that are already there */ ++ if (tmplLine != NULL) { ++ for (j = 2; j < tmplLine->numElements; j++) ++ if (strcmp ++ (extraInitrd, ++ tmplLine->elements[j].item) == 0) ++ break; ++ ++ if (j != tmplLine->numElements) ++ continue; + } + +- } else if (tmplLine->type == LT_MENUENTRY && +- (needs & NEED_TITLE)) { +- requote(tmplLine, config->cfi); +- char *nkt = malloc(strlen(newKernelTitle)+3); +- strcpy(nkt, "'"); +- strcat(nkt, newKernelTitle); +- strcat(nkt, "'"); +- newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi); +- free(nkt); +- needs &= ~NEED_TITLE; +- } else if (tmplLine->type == LT_TITLE && +- (needs & NEED_TITLE)) { +- if (tmplLine->numElements >= 2) { +- newLine = addLineTmpl(new, tmplLine, newLine, +- newKernelTitle, config->cfi); +- needs &= ~NEED_TITLE; +- } else if (tmplLine->numElements == 1 && +- config->cfi->titleBracketed) { +- /* addLineTmpl doesn't handle titleBracketed */ +- newLine = addLine(new, config->cfi, LT_TITLE, +- tmplLine->indent, newKernelTitle); +- needs &= ~NEED_TITLE; ++ *end++ = separatorChar; ++ end = stpcpy(end, extraInitrd); ++ } ++ ++ return initrdVal; ++} ++ ++int addNewKernel(struct grubConfig *config, struct singleEntry *template, ++ const char *prefix, ++ const char *newKernelPath, const char *newKernelTitle, ++ const char *newKernelArgs, const char *newKernelInitrd, ++ const char **extraInitrds, int extraInitrdCount, ++ const char *newMBKernel, const char *newMBKernelArgs) ++{ ++ struct singleEntry *new; ++ struct singleLine *newLine = NULL, *tmplLine = NULL, *masterLine = NULL; ++ int needs; ++ char *chptr; ++ ++ if (!newKernelPath) ++ return 0; ++ ++ /* if the newKernelTitle is too long silently munge it into something ++ * we can live with. truncating is first check, then we'll just mess with ++ * it until it looks better */ ++ if (config->cfi->maxTitleLength && ++ (strlen(newKernelTitle) > config->cfi->maxTitleLength)) { ++ char *buf = alloca(config->cfi->maxTitleLength + 7); ++ char *numBuf = alloca(config->cfi->maxTitleLength + 1); ++ int i = 1; ++ ++ sprintf(buf, "TITLE=%.*s", config->cfi->maxTitleLength, ++ newKernelTitle); ++ while (findEntryByPath(config, buf, NULL, NULL)) { ++ sprintf(numBuf, "%d", i++); ++ strcpy(buf + strlen(buf) - strlen(numBuf), numBuf); + } +- } else if (tmplLine->type == LT_ECHO) { +- requote(tmplLine, config->cfi); +- static const char *prefix = "'Loading "; +- if (tmplLine->numElements > 1 && +- strstr(tmplLine->elements[1].item, prefix) && +- masterLine->next && +- iskernel(masterLine->next->type)) { +- char *newTitle = malloc(strlen(prefix) + +- strlen(newKernelTitle) + 2); +- +- strcpy(newTitle, prefix); +- strcat(newTitle, newKernelTitle); +- strcat(newTitle, "'"); +- newLine = addLine(new, config->cfi, LT_ECHO, +- tmplLine->indent, newTitle); +- free(newTitle); +- } else { +- /* pass through other lines from the template */ +- newLine = addLineTmpl(new, tmplLine, newLine, NULL, +- config->cfi); +- } +- } else { +- /* pass through other lines from the template */ +- newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi); +- } ++ ++ newKernelTitle = buf + 6; + } + +- } else { +- /* don't have a template, so start the entry with the +- * appropriate starting line +- */ +- switch (config->cfi->entryStart) { +- case LT_KERNEL: +- case LT_KERNEL_EFI: +- case LT_KERNEL_16: +- if (new->multiboot && config->cfi->mbHyperFirst) { +- /* fall through to LT_HYPER */ +- } else { +- newLine = addLine(new, config->cfi, +- preferredLineType(LT_KERNEL, config->cfi), +- config->primaryIndent, +- newKernelPath + strlen(prefix)); +- needs &= ~NEED_KERNEL; +- break; ++ new = malloc(sizeof(*new)); ++ new->skip = 0; ++ new->multiboot = 0; ++ new->next = config->entries; ++ new->lines = NULL; ++ config->entries = new; ++ ++ /* copy/update from the template */ ++ needs = NEED_KERNEL | NEED_TITLE; ++ if (newKernelInitrd) ++ needs |= NEED_INITRD; ++ if (newMBKernel) { ++ needs |= NEED_MB; ++ new->multiboot = 1; ++ } ++ ++ if (template) { ++ for (masterLine = template->lines; ++ masterLine && (tmplLine = lineDup(masterLine)); ++ lineFree(tmplLine), masterLine = masterLine->next) { ++ dbgPrintf("addNewKernel processing %d\n", ++ tmplLine->type); ++ ++ /* skip comments */ ++ chptr = tmplLine->indent; ++ while (*chptr && isspace(*chptr)) ++ chptr++; ++ if (*chptr == '#') ++ continue; ++ ++ if (iskernel(tmplLine->type) ++ && tmplLine->numElements >= 2) { ++ if (!template->multiboot && (needs & NEED_MB)) { ++ /* it's not a multiboot template and this is the kernel ++ * line. Try to be intelligent about inserting the ++ * hypervisor at the same time. ++ */ ++ if (config->cfi->mbHyperFirst) { ++ /* insert the hypervisor first */ ++ newLine = ++ addLine(new, config->cfi, ++ LT_HYPER, ++ tmplLine->indent, ++ newMBKernel + ++ strlen(prefix)); ++ /* set up for adding the kernel line */ ++ free(tmplLine->indent); ++ tmplLine->indent = ++ strdup(config-> ++ secondaryIndent); ++ needs &= ~NEED_MB; ++ } ++ if (needs & NEED_KERNEL) { ++ /* use addLineTmpl to preserve line elements, ++ * otherwise we could just call addLine. Unfortunately ++ * this means making some changes to the template ++ * such as the indent change above and the type ++ * change below. ++ */ ++ struct keywordTypes *mbm_kw = ++ getKeywordByType ++ (LT_MBMODULE, config->cfi); ++ if (mbm_kw) { ++ tmplLine->type = ++ LT_MBMODULE; ++ free(tmplLine-> ++ elements[0].item); ++ tmplLine->elements[0]. ++ item = ++ strdup(mbm_kw->key); ++ } ++ newLine = ++ addLineTmpl(new, tmplLine, ++ newLine, ++ newKernelPath + ++ strlen(prefix), ++ config->cfi); ++ needs &= ~NEED_KERNEL; ++ } ++ if (needs & NEED_MB) { /* !mbHyperFirst */ ++ newLine = ++ addLine(new, config->cfi, ++ LT_HYPER, ++ config-> ++ secondaryIndent, ++ newMBKernel + ++ strlen(prefix)); ++ needs &= ~NEED_MB; ++ } ++ } else if (needs & NEED_KERNEL) { ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, ++ newKernelPath + ++ strlen(prefix), ++ config->cfi); ++ needs &= ~NEED_KERNEL; ++ } ++ ++ } else if (tmplLine->type == LT_HYPER && ++ tmplLine->numElements >= 2) { ++ if (needs & NEED_MB) { ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, ++ newMBKernel + ++ strlen(prefix), ++ config->cfi); ++ needs &= ~NEED_MB; ++ } ++ ++ } else if (tmplLine->type == LT_MBMODULE && ++ tmplLine->numElements >= 2) { ++ if (new->multiboot) { ++ if (needs & NEED_KERNEL) { ++ newLine = ++ addLineTmpl(new, tmplLine, ++ newLine, ++ newKernelPath + ++ strlen(prefix), ++ config->cfi); ++ needs &= ~NEED_KERNEL; ++ } else if (config->cfi->mbInitRdIsModule ++ && (needs & NEED_INITRD)) { ++ char *initrdVal; ++ initrdVal = ++ getInitrdVal(config, prefix, ++ tmplLine, ++ newKernelInitrd, ++ extraInitrds, ++ extraInitrdCount); ++ newLine = ++ addLineTmpl(new, tmplLine, ++ newLine, ++ initrdVal, ++ config->cfi); ++ free(initrdVal); ++ needs &= ~NEED_INITRD; ++ } ++ } else if (needs & NEED_KERNEL) { ++ /* template is multi but new is not, ++ * insert the kernel in the first module slot ++ */ ++ tmplLine->type = ++ preferredLineType(LT_KERNEL, ++ config->cfi); ++ free(tmplLine->elements[0].item); ++ tmplLine->elements[0].item = ++ strdup(getKeywordByType ++ (tmplLine->type, ++ config->cfi)->key); ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, ++ newKernelPath + ++ strlen(prefix), ++ config->cfi); ++ needs &= ~NEED_KERNEL; ++ } else if (needs & NEED_INITRD) { ++ char *initrdVal; ++ /* template is multi but new is not, ++ * insert the initrd in the second module slot ++ */ ++ tmplLine->type = ++ preferredLineType(LT_INITRD, ++ config->cfi); ++ free(tmplLine->elements[0].item); ++ tmplLine->elements[0].item = ++ strdup(getKeywordByType ++ (tmplLine->type, ++ config->cfi)->key); ++ initrdVal = ++ getInitrdVal(config, prefix, ++ tmplLine, ++ newKernelInitrd, ++ extraInitrds, ++ extraInitrdCount); ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, ++ initrdVal, config->cfi); ++ free(initrdVal); ++ needs &= ~NEED_INITRD; ++ } ++ ++ } else if (isinitrd(tmplLine->type) ++ && tmplLine->numElements >= 2) { ++ if (needs & NEED_INITRD && new->multiboot ++ && !template->multiboot ++ && config->cfi->mbInitRdIsModule) { ++ /* make sure we don't insert the module initrd ++ * before the module kernel... if we don't do it here, ++ * it will be inserted following the template. ++ */ ++ if (!needs & NEED_KERNEL) { ++ char *initrdVal; ++ ++ initrdVal = ++ getInitrdVal(config, prefix, ++ tmplLine, ++ newKernelInitrd, ++ extraInitrds, ++ extraInitrdCount); ++ newLine = ++ addLine(new, config->cfi, ++ LT_MBMODULE, ++ config-> ++ secondaryIndent, ++ initrdVal); ++ free(initrdVal); ++ needs &= ~NEED_INITRD; ++ } ++ } else if (needs & NEED_INITRD) { ++ char *initrdVal; ++ initrdVal = ++ getInitrdVal(config, prefix, ++ tmplLine, ++ newKernelInitrd, ++ extraInitrds, ++ extraInitrdCount); ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, ++ initrdVal, config->cfi); ++ free(initrdVal); ++ needs &= ~NEED_INITRD; ++ } ++ ++ } else if (tmplLine->type == LT_MENUENTRY && ++ (needs & NEED_TITLE)) { ++ requote(tmplLine, config->cfi); ++ char *nkt = malloc(strlen(newKernelTitle) + 3); ++ strcpy(nkt, "'"); ++ strcat(nkt, newKernelTitle); ++ strcat(nkt, "'"); ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, nkt, ++ config->cfi); ++ free(nkt); ++ needs &= ~NEED_TITLE; ++ } else if (tmplLine->type == LT_TITLE && ++ (needs & NEED_TITLE)) { ++ if (tmplLine->numElements >= 2) { ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, ++ newKernelTitle, ++ config->cfi); ++ needs &= ~NEED_TITLE; ++ } else if (tmplLine->numElements == 1 && ++ config->cfi->titleBracketed) { ++ /* addLineTmpl doesn't handle titleBracketed */ ++ newLine = ++ addLine(new, config->cfi, LT_TITLE, ++ tmplLine->indent, ++ newKernelTitle); ++ needs &= ~NEED_TITLE; ++ } ++ } else if (tmplLine->type == LT_ECHO) { ++ requote(tmplLine, config->cfi); ++ static const char *prefix = "'Loading "; ++ if (tmplLine->numElements > 1 && ++ strstr(tmplLine->elements[1].item, prefix) ++ && masterLine->next ++ && iskernel(masterLine->next->type)) { ++ char *newTitle = ++ malloc(strlen(prefix) + ++ strlen(newKernelTitle) + 2); ++ ++ strcpy(newTitle, prefix); ++ strcat(newTitle, newKernelTitle); ++ strcat(newTitle, "'"); ++ newLine = ++ addLine(new, config->cfi, LT_ECHO, ++ tmplLine->indent, newTitle); ++ free(newTitle); ++ } else { ++ /* pass through other lines from the template */ ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, ++ NULL, config->cfi); ++ } ++ } else { ++ /* pass through other lines from the template */ ++ newLine = ++ addLineTmpl(new, tmplLine, newLine, NULL, ++ config->cfi); ++ } + } + +- case LT_HYPER: +- newLine = addLine(new, config->cfi, LT_HYPER, +- config->primaryIndent, +- newMBKernel + strlen(prefix)); +- needs &= ~NEED_MB; +- break; ++ } else { ++ /* don't have a template, so start the entry with the ++ * appropriate starting line ++ */ ++ switch (config->cfi->entryStart) { ++ case LT_KERNEL: ++ case LT_KERNEL_EFI: ++ case LT_KERNEL_16: ++ if (new->multiboot && config->cfi->mbHyperFirst) { ++ /* fall through to LT_HYPER */ ++ } else { ++ newLine = addLine(new, config->cfi, ++ preferredLineType(LT_KERNEL, ++ config-> ++ cfi), ++ config->primaryIndent, ++ newKernelPath + ++ strlen(prefix)); ++ needs &= ~NEED_KERNEL; ++ break; ++ } + +- case LT_MENUENTRY: { +- char *nkt = malloc(strlen(newKernelTitle)+3); +- strcpy(nkt, "'"); +- strcat(nkt, newKernelTitle); +- strcat(nkt, "'"); +- newLine = addLine(new, config->cfi, LT_MENUENTRY, +- config->primaryIndent, nkt); +- free(nkt); +- needs &= ~NEED_TITLE; +- needs |= NEED_END; +- break; +- } +- case LT_TITLE: +- if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above) +- char * templabel; +- int x = 0, y = 0; +- +- templabel = strdup(newKernelTitle); +- while( templabel[x]){ +- if( templabel[x] == ' ' ){ +- y = x; +- while( templabel[y] ){ +- templabel[y] = templabel[y+1]; +- y++; ++ case LT_HYPER: ++ newLine = addLine(new, config->cfi, LT_HYPER, ++ config->primaryIndent, ++ newMBKernel + strlen(prefix)); ++ needs &= ~NEED_MB; ++ break; ++ ++ case LT_MENUENTRY:{ ++ char *nkt = malloc(strlen(newKernelTitle) + 3); ++ strcpy(nkt, "'"); ++ strcat(nkt, newKernelTitle); ++ strcat(nkt, "'"); ++ newLine = ++ addLine(new, config->cfi, LT_MENUENTRY, ++ config->primaryIndent, nkt); ++ free(nkt); ++ needs &= ~NEED_TITLE; ++ needs |= NEED_END; ++ break; ++ } ++ case LT_TITLE: ++ if (useextlinuxmenu != 0) { // We just need useextlinuxmenu to not be zero (set above) ++ char *templabel; ++ int x = 0, y = 0; ++ ++ templabel = strdup(newKernelTitle); ++ while (templabel[x]) { ++ if (templabel[x] == ' ') { ++ y = x; ++ while (templabel[y]) { ++ templabel[y] = ++ templabel[y + 1]; ++ y++; ++ } + } ++ x++; + } +- x++; ++ newLine = addLine(new, config->cfi, LT_TITLE, ++ config->primaryIndent, ++ templabel); ++ free(templabel); ++ } else { ++ newLine = addLine(new, config->cfi, LT_TITLE, ++ config->primaryIndent, ++ newKernelTitle); + } +- newLine = addLine(new, config->cfi, LT_TITLE, +- config->primaryIndent, templabel); +- free(templabel); +- }else{ +- newLine = addLine(new, config->cfi, LT_TITLE, +- config->primaryIndent, newKernelTitle); ++ needs &= ~NEED_TITLE; ++ break; ++ ++ default: ++ abort(); + } ++ } ++ ++ struct singleLine *endLine = NULL; ++ endLine = getLineByType(LT_ENTRY_END, new->lines); ++ if (endLine) { ++ removeLine(new, endLine); ++ needs |= NEED_END; ++ } ++ ++ /* add the remainder of the lines, i.e. those that either ++ * weren't present in the template, or in the case of no template, ++ * all the lines following the entryStart. ++ */ ++ if (needs & NEED_TITLE) { ++ newLine = addLine(new, config->cfi, LT_TITLE, ++ config->secondaryIndent, newKernelTitle); + needs &= ~NEED_TITLE; +- break; ++ } ++ if ((needs & NEED_MB) && config->cfi->mbHyperFirst) { ++ newLine = addLine(new, config->cfi, LT_HYPER, ++ config->secondaryIndent, ++ newMBKernel + strlen(prefix)); ++ needs &= ~NEED_MB; ++ } ++ if (needs & NEED_KERNEL) { ++ newLine = addLine(new, config->cfi, ++ (new->multiboot ++ && getKeywordByType(LT_MBMODULE, ++ config->cfi)) ++ ? LT_MBMODULE : preferredLineType(LT_KERNEL, ++ config-> ++ cfi), ++ config->secondaryIndent, ++ newKernelPath + strlen(prefix)); ++ needs &= ~NEED_KERNEL; ++ } ++ if (needs & NEED_MB) { ++ newLine = addLine(new, config->cfi, LT_HYPER, ++ config->secondaryIndent, ++ newMBKernel + strlen(prefix)); ++ needs &= ~NEED_MB; ++ } ++ if (needs & NEED_INITRD) { ++ char *initrdVal; ++ initrdVal = ++ getInitrdVal(config, prefix, NULL, newKernelInitrd, ++ extraInitrds, extraInitrdCount); ++ newLine = ++ addLine(new, config->cfi, ++ (new->multiboot ++ && getKeywordByType(LT_MBMODULE, config->cfi)) ++ ? LT_MBMODULE : preferredLineType(LT_INITRD, ++ config->cfi), ++ config->secondaryIndent, initrdVal); ++ free(initrdVal); ++ needs &= ~NEED_INITRD; ++ } ++ if (needs & NEED_END) { ++ newLine = addLine(new, config->cfi, LT_ENTRY_END, ++ config->secondaryIndent, NULL); ++ needs &= ~NEED_END; ++ } + +- default: ++ if (needs) { ++ printf(_("grubby: needs=%d, aborting\n"), needs); + abort(); + } +- } +- +- struct singleLine *endLine = NULL; +- endLine = getLineByType(LT_ENTRY_END, new->lines); +- if (endLine) { +- removeLine(new, endLine); +- needs |= NEED_END; +- } +- +- /* add the remainder of the lines, i.e. those that either +- * weren't present in the template, or in the case of no template, +- * all the lines following the entryStart. +- */ +- if (needs & NEED_TITLE) { +- newLine = addLine(new, config->cfi, LT_TITLE, +- config->secondaryIndent, +- newKernelTitle); +- needs &= ~NEED_TITLE; +- } +- if ((needs & NEED_MB) && config->cfi->mbHyperFirst) { +- newLine = addLine(new, config->cfi, LT_HYPER, +- config->secondaryIndent, +- newMBKernel + strlen(prefix)); +- needs &= ~NEED_MB; +- } +- if (needs & NEED_KERNEL) { +- newLine = addLine(new, config->cfi, +- (new->multiboot && getKeywordByType(LT_MBMODULE, +- config->cfi)) +- ? LT_MBMODULE +- : preferredLineType(LT_KERNEL, config->cfi), +- config->secondaryIndent, +- newKernelPath + strlen(prefix)); +- needs &= ~NEED_KERNEL; +- } +- if (needs & NEED_MB) { +- newLine = addLine(new, config->cfi, LT_HYPER, +- config->secondaryIndent, +- newMBKernel + strlen(prefix)); +- needs &= ~NEED_MB; +- } +- if (needs & NEED_INITRD) { +- char *initrdVal; +- initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount); +- newLine = addLine(new, config->cfi, +- (new->multiboot && getKeywordByType(LT_MBMODULE, +- config->cfi)) +- ? LT_MBMODULE +- : preferredLineType(LT_INITRD, config->cfi), +- config->secondaryIndent, +- initrdVal); +- free(initrdVal); +- needs &= ~NEED_INITRD; +- } +- if (needs & NEED_END) { +- newLine = addLine(new, config->cfi, LT_ENTRY_END, +- config->secondaryIndent, NULL); +- needs &= ~NEED_END; +- } +- +- if (needs) { +- printf(_("grubby: needs=%d, aborting\n"), needs); +- abort(); +- } +- +- if (updateImage(config, "0", prefix, newKernelArgs, NULL, +- newMBKernelArgs, NULL)) return 1; +- +- return 0; ++ ++ if (updateImage(config, "0", prefix, newKernelArgs, NULL, ++ newMBKernelArgs, NULL)) ++ return 1; ++ ++ return 0; + } + +-int main(int argc, const char ** argv) { +- poptContext optCon; +- const char * grubConfig = NULL; +- char * outputFile = NULL; +- int arg = 0; +- int flags = 0; +- int badImageOkay = 0; +- int configureGrub2 = 0; +- int configureLilo = 0, configureELilo = 0, configureGrub = 0; +- int configureYaboot = 0, configureSilo = 0, configureZipl = 0; +- int configureExtLinux = 0; +- int bootloaderProbe = 0; +- int extraInitrdCount = 0; +- char * updateKernelPath = NULL; +- char * newKernelPath = NULL; +- char * removeKernelPath = NULL; +- char * newKernelArgs = NULL; +- char * newKernelInitrd = NULL; +- char * newKernelTitle = NULL; +- char * newKernelVersion = NULL; +- char * newMBKernel = NULL; +- char * newMBKernelArgs = NULL; +- char * removeMBKernelArgs = NULL; +- char * removeMBKernel = NULL; +- char * bootPrefix = NULL; +- char * defaultKernel = NULL; +- char * removeArgs = NULL; +- char * kernelInfo = NULL; +- char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL }; +- char * envPath = NULL; +- const char * chptr = NULL; +- struct configFileInfo * cfi = NULL; +- struct grubConfig * config; +- struct singleEntry * template = NULL; +- int copyDefault = 0, makeDefault = 0; +- int displayDefault = 0; +- int displayDefaultIndex = 0; +- int displayDefaultTitle = 0; +- int defaultIndex = -1; +- struct poptOption options[] = { +- { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0, +- _("add an entry for the specified kernel"), _("kernel-path") }, +- { "add-multiboot", 0, POPT_ARG_STRING, &newMBKernel, 0, +- _("add an entry for the specified multiboot kernel"), NULL }, +- { "args", 0, POPT_ARG_STRING, &newKernelArgs, 0, +- _("default arguments for the new kernel or new arguments for " +- "kernel being updated"), _("args") }, +- { "mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0, +- _("default arguments for the new multiboot kernel or " +- "new arguments for multiboot kernel being updated"), NULL }, +- { "bad-image-okay", 0, 0, &badImageOkay, 0, +- _("don't sanity check images in boot entries (for testing only)"), +- NULL }, +- { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0, +- _("filestystem which contains /boot directory (for testing only)"), +- _("bootfs") }, ++int main(int argc, const char **argv) ++{ ++ poptContext optCon; ++ const char *grubConfig = NULL; ++ char *outputFile = NULL; ++ int arg = 0; ++ int flags = 0; ++ int badImageOkay = 0; ++ int configureGrub2 = 0; ++ int configureLilo = 0, configureELilo = 0, configureGrub = 0; ++ int configureYaboot = 0, configureSilo = 0, configureZipl = 0; ++ int configureExtLinux = 0; ++ int bootloaderProbe = 0; ++ int extraInitrdCount = 0; ++ char *updateKernelPath = NULL; ++ char *newKernelPath = NULL; ++ char *removeKernelPath = NULL; ++ char *newKernelArgs = NULL; ++ char *newKernelInitrd = NULL; ++ char *newKernelTitle = NULL; ++ char *newKernelVersion = NULL; ++ char *newMBKernel = NULL; ++ char *newMBKernelArgs = NULL; ++ char *removeMBKernelArgs = NULL; ++ char *removeMBKernel = NULL; ++ char *bootPrefix = NULL; ++ char *defaultKernel = NULL; ++ char *removeArgs = NULL; ++ char *kernelInfo = NULL; ++ char *extraInitrds[MAX_EXTRA_INITRDS] = { NULL }; ++ char *envPath = NULL; ++ const char *chptr = NULL; ++ struct configFileInfo *cfi = NULL; ++ struct grubConfig *config; ++ struct singleEntry *template = NULL; ++ int copyDefault = 0, makeDefault = 0; ++ int displayDefault = 0; ++ int displayDefaultIndex = 0; ++ int displayDefaultTitle = 0; ++ int defaultIndex = -1; ++ struct poptOption options[] = { ++ {"add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0, ++ _("add an entry for the specified kernel"), _("kernel-path")}, ++ {"add-multiboot", 0, POPT_ARG_STRING, &newMBKernel, 0, ++ _("add an entry for the specified multiboot kernel"), NULL}, ++ {"args", 0, POPT_ARG_STRING, &newKernelArgs, 0, ++ _("default arguments for the new kernel or new arguments for " ++ "kernel being updated"), _("args")}, ++ {"mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0, ++ _("default arguments for the new multiboot kernel or " ++ "new arguments for multiboot kernel being updated"), NULL}, ++ {"bad-image-okay", 0, 0, &badImageOkay, 0, ++ _ ++ ("don't sanity check images in boot entries (for testing only)"), ++ NULL}, ++ {"boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0, ++ _ ++ ("filestystem which contains /boot directory (for testing only)"), ++ _("bootfs")}, + #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__) +- { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0, +- _("check which bootloader is installed on boot sector") }, ++ {"bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0, ++ _("check which bootloader is installed on boot sector")}, + #endif +- { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0, +- _("path to grub config file to update (\"-\" for stdin)"), +- _("path") }, +- { "copy-default", 0, 0, ©Default, 0, +- _("use the default boot entry as a template for the new entry " +- "being added; if the default is not a linux image, or if " +- "the kernel referenced by the default image does not exist, " +- "the first linux entry whose kernel does exist is used as the " +- "template"), NULL }, +- { "debug", 0, 0, &debug, 0, +- _("print debugging information for failures") }, +- { "default-kernel", 0, 0, &displayDefault, 0, +- _("display the path of the default kernel") }, +- { "default-index", 0, 0, &displayDefaultIndex, 0, +- _("display the index of the default kernel") }, +- { "default-title", 0, 0, &displayDefaultTitle, 0, +- _("display the title of the default kernel") }, +- { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0, +- _("configure elilo bootloader") }, +- { "efi", 0, POPT_ARG_NONE, &isEfi, 0, +- _("force grub2 stanzas to use efi") }, +- { "env", 0, POPT_ARG_STRING, &envPath, 0, +- _("path for environment data"), +- _("path") }, +- { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0, +- _("configure extlinux bootloader (from syslinux)") }, +- { "grub", 0, POPT_ARG_NONE, &configureGrub, 0, +- _("configure grub bootloader") }, +- { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0, +- _("configure grub2 bootloader") }, +- { "info", 0, POPT_ARG_STRING, &kernelInfo, 0, +- _("display boot information for specified kernel"), +- _("kernel-path") }, +- { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0, +- _("initrd image for the new kernel"), _("initrd-path") }, +- { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i', +- _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") }, +- { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0, +- _("configure lilo bootloader") }, +- { "make-default", 0, 0, &makeDefault, 0, +- _("make the newly added entry the default boot entry"), NULL }, +- { "output-file", 'o', POPT_ARG_STRING, &outputFile, 0, +- _("path to output updated config file (\"-\" for stdout)"), +- _("path") }, +- { "remove-args", 0, POPT_ARG_STRING, &removeArgs, 0, +- _("remove kernel arguments"), NULL }, +- { "remove-mbargs", 0, POPT_ARG_STRING, &removeMBKernelArgs, 0, +- _("remove multiboot kernel arguments"), NULL }, +- { "remove-kernel", 0, POPT_ARG_STRING, &removeKernelPath, 0, +- _("remove all entries for the specified kernel"), +- _("kernel-path") }, +- { "remove-multiboot", 0, POPT_ARG_STRING, &removeMBKernel, 0, +- _("remove all entries for the specified multiboot kernel"), NULL }, +- { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0, +- _("make the first entry referencing the specified kernel " +- "the default"), _("kernel-path") }, +- { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0, +- _("make the given entry index the default entry"), +- _("entry-index") }, +- { "silo", 0, POPT_ARG_NONE, &configureSilo, 0, +- _("configure silo bootloader") }, +- { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0, +- _("title to use for the new kernel entry"), _("entry-title") }, +- { "update-kernel", 0, POPT_ARG_STRING, &updateKernelPath, 0, +- _("updated information for the specified kernel"), +- _("kernel-path") }, +- { "version", 'v', 0, NULL, 'v', +- _("print the version of this program and exit"), NULL }, +- { "yaboot", 0, POPT_ARG_NONE, &configureYaboot, 0, +- _("configure yaboot bootloader") }, +- { "zipl", 0, POPT_ARG_NONE, &configureZipl, 0, +- _("configure zipl bootloader") }, +- POPT_AUTOHELP +- { 0, 0, 0, 0, 0 } +- }; +- +- useextlinuxmenu=0; +- +- int i = 0; +- for (int j = 1; j < argc; j++) +- i += strlen(argv[j]) + 1; +- saved_command_line = malloc(i); +- if (!saved_command_line) { +- fprintf(stderr, "grubby: %m\n"); +- exit(1); +- } +- saved_command_line[0] = '\0'; +- for (int j = 1; j < argc; j++) { +- strcat(saved_command_line, argv[j]); +- strncat(saved_command_line, j == argc -1 ? "" : " ", 1); +- } +- +- optCon = poptGetContext("grubby", argc, argv, options, 0); +- poptReadDefaultConfig(optCon, 1); +- +- while ((arg = poptGetNextOpt(optCon)) >= 0) { +- switch (arg) { +- case 'v': +- printf("grubby version %s\n", VERSION); +- exit(0); +- break; +- case 'i': +- if (extraInitrdCount < MAX_EXTRA_INITRDS) { +- extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon)); +- } else { +- fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount); ++ {"config-file", 'c', POPT_ARG_STRING, &grubConfig, 0, ++ _("path to grub config file to update (\"-\" for stdin)"), ++ _("path")}, ++ {"copy-default", 0, 0, ©Default, 0, ++ _("use the default boot entry as a template for the new entry " ++ "being added; if the default is not a linux image, or if " ++ "the kernel referenced by the default image does not exist, " ++ "the first linux entry whose kernel does exist is used as the " ++ "template"), NULL}, ++ {"debug", 0, 0, &debug, 0, ++ _("print debugging information for failures")}, ++ {"default-kernel", 0, 0, &displayDefault, 0, ++ _("display the path of the default kernel")}, ++ {"default-index", 0, 0, &displayDefaultIndex, 0, ++ _("display the index of the default kernel")}, ++ {"default-title", 0, 0, &displayDefaultTitle, 0, ++ _("display the title of the default kernel")}, ++ {"elilo", 0, POPT_ARG_NONE, &configureELilo, 0, ++ _("configure elilo bootloader")}, ++ {"efi", 0, POPT_ARG_NONE, &isEfi, 0, ++ _("force grub2 stanzas to use efi")}, ++ {"env", 0, POPT_ARG_STRING, &envPath, 0, ++ _("path for environment data"), ++ _("path")}, ++ {"extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0, ++ _("configure extlinux bootloader (from syslinux)")}, ++ {"grub", 0, POPT_ARG_NONE, &configureGrub, 0, ++ _("configure grub bootloader")}, ++ {"grub2", 0, POPT_ARG_NONE, &configureGrub2, 0, ++ _("configure grub2 bootloader")}, ++ {"info", 0, POPT_ARG_STRING, &kernelInfo, 0, ++ _("display boot information for specified kernel"), ++ _("kernel-path")}, ++ {"initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0, ++ _("initrd image for the new kernel"), _("initrd-path")}, ++ {"extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i', ++ _ ++ ("auxiliary initrd image for things other than the new kernel"), ++ _("initrd-path")}, ++ {"lilo", 0, POPT_ARG_NONE, &configureLilo, 0, ++ _("configure lilo bootloader")}, ++ {"make-default", 0, 0, &makeDefault, 0, ++ _("make the newly added entry the default boot entry"), NULL}, ++ {"output-file", 'o', POPT_ARG_STRING, &outputFile, 0, ++ _("path to output updated config file (\"-\" for stdout)"), ++ _("path")}, ++ {"remove-args", 0, POPT_ARG_STRING, &removeArgs, 0, ++ _("remove kernel arguments"), NULL}, ++ {"remove-mbargs", 0, POPT_ARG_STRING, &removeMBKernelArgs, 0, ++ _("remove multiboot kernel arguments"), NULL}, ++ {"remove-kernel", 0, POPT_ARG_STRING, &removeKernelPath, 0, ++ _("remove all entries for the specified kernel"), ++ _("kernel-path")}, ++ {"remove-multiboot", 0, POPT_ARG_STRING, &removeMBKernel, 0, ++ _("remove all entries for the specified multiboot kernel"), ++ NULL}, ++ {"set-default", 0, POPT_ARG_STRING, &defaultKernel, 0, ++ _("make the first entry referencing the specified kernel " ++ "the default"), _("kernel-path")}, ++ {"set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0, ++ _("make the given entry index the default entry"), ++ _("entry-index")}, ++ {"silo", 0, POPT_ARG_NONE, &configureSilo, 0, ++ _("configure silo bootloader")}, ++ {"title", 0, POPT_ARG_STRING, &newKernelTitle, 0, ++ _("title to use for the new kernel entry"), _("entry-title")}, ++ {"update-kernel", 0, POPT_ARG_STRING, &updateKernelPath, 0, ++ _("updated information for the specified kernel"), ++ _("kernel-path")}, ++ {"version", 'v', 0, NULL, 'v', ++ _("print the version of this program and exit"), NULL}, ++ {"yaboot", 0, POPT_ARG_NONE, &configureYaboot, 0, ++ _("configure yaboot bootloader")}, ++ {"zipl", 0, POPT_ARG_NONE, &configureZipl, 0, ++ _("configure zipl bootloader")}, ++ POPT_AUTOHELP {0, 0, 0, 0, 0} ++ }; ++ ++ useextlinuxmenu = 0; ++ ++ int i = 0; ++ for (int j = 1; j < argc; j++) ++ i += strlen(argv[j]) + 1; ++ saved_command_line = malloc(i); ++ if (!saved_command_line) { ++ fprintf(stderr, "grubby: %m\n"); ++ exit(1); ++ } ++ saved_command_line[0] = '\0'; ++ for (int j = 1; j < argc; j++) { ++ strcat(saved_command_line, argv[j]); ++ strncat(saved_command_line, j == argc - 1 ? "" : " ", 1); ++ } ++ ++ optCon = poptGetContext("grubby", argc, argv, options, 0); ++ poptReadDefaultConfig(optCon, 1); ++ ++ while ((arg = poptGetNextOpt(optCon)) >= 0) { ++ switch (arg) { ++ case 'v': ++ printf("grubby version %s\n", VERSION); ++ exit(0); ++ break; ++ case 'i': ++ if (extraInitrdCount < MAX_EXTRA_INITRDS) { ++ extraInitrds[extraInitrdCount++] = ++ strdup(poptGetOptArg(optCon)); ++ } else { ++ fprintf(stderr, ++ _ ++ ("grubby: extra initrd maximum is %d\n"), ++ extraInitrdCount); ++ return 1; ++ } ++ break; ++ } ++ } ++ ++ if (arg < -1) { ++ fprintf(stderr, _("grubby: bad argument %s: %s\n"), ++ poptBadOption(optCon, POPT_BADOPTION_NOALIAS), ++ poptStrerror(arg)); + return 1; +- } +- break; + } +- } + +- if (arg < -1) { +- fprintf(stderr, _("grubby: bad argument %s: %s\n"), +- poptBadOption(optCon, POPT_BADOPTION_NOALIAS), +- poptStrerror(arg)); +- return 1; +- } ++ if ((chptr = poptGetArg(optCon))) { ++ fprintf(stderr, _("grubby: unexpected argument %s\n"), chptr); ++ return 1; ++ } + +- if ((chptr = poptGetArg(optCon))) { +- fprintf(stderr, _("grubby: unexpected argument %s\n"), chptr); +- return 1; +- } ++ if ((configureLilo + configureGrub2 + configureGrub + configureELilo + ++ configureYaboot + configureSilo + configureZipl + ++ configureExtLinux) > 1) { ++ fprintf(stderr, ++ _("grubby: cannot specify multiple bootloaders\n")); ++ return 1; ++ } else if (bootloaderProbe && grubConfig) { ++ fprintf(stderr, ++ _ ++ ("grubby: cannot specify config file with --bootloader-probe\n")); ++ return 1; ++ } else if (configureGrub2) { ++ cfi = &grub2ConfigType; ++ if (envPath) ++ cfi->envFile = envPath; ++ } else if (configureLilo) { ++ cfi = &liloConfigType; ++ } else if (configureGrub) { ++ cfi = &grubConfigType; ++ } else if (configureELilo) { ++ cfi = &eliloConfigType; ++ } else if (configureYaboot) { ++ cfi = &yabootConfigType; ++ } else if (configureSilo) { ++ cfi = &siloConfigType; ++ } else if (configureZipl) { ++ cfi = &ziplConfigType; ++ } else if (configureExtLinux) { ++ cfi = &extlinuxConfigType; ++ useextlinuxmenu = 1; ++ } + +- if ((configureLilo + configureGrub2 + configureGrub + configureELilo + +- configureYaboot + configureSilo + configureZipl + +- configureExtLinux ) > 1) { +- fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n")); +- return 1; +- } else if (bootloaderProbe && grubConfig) { +- fprintf(stderr, +- _("grubby: cannot specify config file with --bootloader-probe\n")); +- return 1; +- } else if (configureGrub2) { +- cfi = &grub2ConfigType; +- if (envPath) +- cfi->envFile = envPath; +- } else if (configureLilo) { +- cfi = &liloConfigType; +- } else if (configureGrub) { +- cfi = &grubConfigType; +- } else if (configureELilo) { +- cfi = &eliloConfigType; +- } else if (configureYaboot) { +- cfi = &yabootConfigType; +- } else if (configureSilo) { +- cfi = &siloConfigType; +- } else if (configureZipl) { +- cfi = &ziplConfigType; +- } else if (configureExtLinux) { +- cfi = &extlinuxConfigType; +- useextlinuxmenu=1; +- } +- +- if (!cfi) { +- if (grub2FindConfig(&grub2ConfigType)) { +- cfi = &grub2ConfigType; +- if (envPath) +- cfi->envFile = envPath; +- } else +- #ifdef __ia64__ +- cfi = &eliloConfigType; +- #elif __powerpc__ +- cfi = &yabootConfigType; +- #elif __sparc__ +- cfi = &siloConfigType; +- #elif __s390__ +- cfi = &ziplConfigType; +- #elif __s390x__ +- cfi = &ziplConfigtype; +- #else +- cfi = &grubConfigType; +- #endif +- } +- +- if (!grubConfig) { +- if (cfi->findConfig) +- grubConfig = cfi->findConfig(cfi); +- if (!grubConfig) +- grubConfig = cfi->defaultConfig; +- } +- +- if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion || +- newKernelPath || removeKernelPath || makeDefault || +- defaultKernel || displayDefaultIndex || displayDefaultTitle || +- (defaultIndex >= 0))) { +- fprintf(stderr, _("grubby: --bootloader-probe may not be used with " ++ if (!cfi) { ++ if (grub2FindConfig(&grub2ConfigType)) { ++ cfi = &grub2ConfigType; ++ if (envPath) ++ cfi->envFile = envPath; ++ } else ++#ifdef __ia64__ ++ cfi = &eliloConfigType; ++#elif __powerpc__ ++ cfi = &yabootConfigType; ++#elif __sparc__ ++ cfi = &siloConfigType; ++#elif __s390__ ++ cfi = &ziplConfigType; ++#elif __s390x__ ++ cfi = &ziplConfigtype; ++#else ++ cfi = &grubConfigType; ++#endif ++ } ++ ++ if (!grubConfig) { ++ if (cfi->findConfig) ++ grubConfig = cfi->findConfig(cfi); ++ if (!grubConfig) ++ grubConfig = cfi->defaultConfig; ++ } ++ ++ if (bootloaderProbe ++ && (displayDefault || kernelInfo || newKernelVersion ++ || newKernelPath || removeKernelPath || makeDefault ++ || defaultKernel || displayDefaultIndex || displayDefaultTitle ++ || (defaultIndex >= 0))) { ++ fprintf(stderr, ++ _("grubby: --bootloader-probe may not be used with " + "specified option")); +- return 1; +- } ++ return 1; ++ } + +- if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath || +- removeKernelPath)) { +- fprintf(stderr, _("grubby: --default-kernel and --info may not " ++ if ((displayDefault || kernelInfo) ++ && (newKernelVersion || newKernelPath || removeKernelPath)) { ++ fprintf(stderr, ++ _("grubby: --default-kernel and --info may not " + "be used when adding or removing kernels\n")); +- return 1; +- } ++ return 1; ++ } + +- if (newKernelPath && !newKernelTitle) { +- fprintf(stderr, _("grubby: kernel title must be specified\n")); +- return 1; +- } else if (!newKernelPath && (copyDefault || +- (newKernelInitrd && !updateKernelPath)|| +- makeDefault || extraInitrdCount > 0)) { +- fprintf(stderr, _("grubby: kernel path expected\n")); +- return 1; +- } ++ if (newKernelPath && !newKernelTitle) { ++ fprintf(stderr, _("grubby: kernel title must be specified\n")); ++ return 1; ++ } else if (!newKernelPath && (copyDefault || ++ (newKernelInitrd && !updateKernelPath) || ++ makeDefault || extraInitrdCount > 0)) { ++ fprintf(stderr, _("grubby: kernel path expected\n")); ++ return 1; ++ } + +- if (newKernelPath && updateKernelPath) { +- fprintf(stderr, _("grubby: --add-kernel and --update-kernel may" +- "not be used together")); +- return 1; +- } ++ if (newKernelPath && updateKernelPath) { ++ fprintf(stderr, _("grubby: --add-kernel and --update-kernel may" ++ "not be used together")); ++ return 1; ++ } + +- if (makeDefault && defaultKernel) { +- fprintf(stderr, _("grubby: --make-default and --default-kernel " +- "may not be used together\n")); +- return 1; +- } else if (defaultKernel && removeKernelPath && +- !strcmp(defaultKernel, removeKernelPath)) { +- fprintf(stderr, _("grubby: cannot make removed kernel the default\n")); +- return 1; +- } else if (defaultKernel && newKernelPath && +- !strcmp(defaultKernel, newKernelPath)) { +- makeDefault = 1; +- defaultKernel = NULL; +- } +- else if (defaultKernel && (defaultIndex >= 0)) { +- fprintf(stderr, _("grubby: --set-default and --set-default-index " ++ if (makeDefault && defaultKernel) { ++ fprintf(stderr, _("grubby: --make-default and --default-kernel " ++ "may not be used together\n")); ++ return 1; ++ } else if (defaultKernel && removeKernelPath && ++ !strcmp(defaultKernel, removeKernelPath)) { ++ fprintf(stderr, ++ _("grubby: cannot make removed kernel the default\n")); ++ return 1; ++ } else if (defaultKernel && newKernelPath && ++ !strcmp(defaultKernel, newKernelPath)) { ++ makeDefault = 1; ++ defaultKernel = NULL; ++ } else if (defaultKernel && (defaultIndex >= 0)) { ++ fprintf(stderr, ++ _("grubby: --set-default and --set-default-index " + "may not be used together\n")); +- return 1; +- } ++ return 1; ++ } + +- if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) { +- fprintf(stderr, _("grubby: output file must be specified if stdin " +- "is used\n")); +- return 1; +- } ++ if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) { ++ fprintf(stderr, ++ _("grubby: output file must be specified if stdin " ++ "is used\n")); ++ return 1; ++ } + +- if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel +- && !kernelInfo && !bootloaderProbe && !updateKernelPath +- && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle +- && (defaultIndex == -1)) { +- fprintf(stderr, _("grubby: no action specified\n")); +- return 1; +- } ++ if (!removeKernelPath && !newKernelPath && !displayDefault ++ && !defaultKernel && !kernelInfo && !bootloaderProbe ++ && !updateKernelPath && !removeMBKernel && !displayDefaultIndex ++ && !displayDefaultTitle && (defaultIndex == -1)) { ++ fprintf(stderr, _("grubby: no action specified\n")); ++ return 1; ++ } + +- flags |= badImageOkay ? GRUBBY_BADIMAGE_OKAY : 0; ++ flags |= badImageOkay ? GRUBBY_BADIMAGE_OKAY : 0; + +- if (cfi->needsBootPrefix) { +- if (!bootPrefix) { +- bootPrefix = findBootPrefix(); +- if (!bootPrefix) return 1; ++ if (cfi->needsBootPrefix) { ++ if (!bootPrefix) { ++ bootPrefix = findBootPrefix(); ++ if (!bootPrefix) ++ return 1; ++ } else { ++ /* this shouldn't end with a / */ ++ if (bootPrefix[strlen(bootPrefix) - 1] == '/') ++ bootPrefix[strlen(bootPrefix) - 1] = '\0'; ++ } + } else { +- /* this shouldn't end with a / */ +- if (bootPrefix[strlen(bootPrefix) - 1] == '/') +- bootPrefix[strlen(bootPrefix) - 1] = '\0'; ++ bootPrefix = ""; + } +- } else { +- bootPrefix = ""; +- } +- +- if (!cfi->mbAllowExtraInitRds && +- extraInitrdCount > 0) { +- fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig); +- return 1; +- } +- +- if (bootloaderProbe) { +- int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0; +- struct grubConfig * lconfig, * gconfig, * yconfig, * econfig; +- +- const char *grub2config = grub2FindConfig(&grub2ConfigType); +- if (grub2config) { +- gconfig = readConfig(grub2config, &grub2ConfigType); +- if (!gconfig) +- gr2c = 1; +- else +- gr2c = checkForGrub2(gconfig); +- } +- +- const char *grubconfig = grubFindConfig(&grubConfigType); +- if (!access(grubconfig, F_OK)) { +- gconfig = readConfig(grubconfig, &grubConfigType); +- if (!gconfig) +- grc = 1; +- else +- grc = checkForGrub(gconfig); +- } +- +- if (!access(liloConfigType.defaultConfig, F_OK)) { +- lconfig = readConfig(liloConfigType.defaultConfig, &liloConfigType); +- if (!lconfig) +- lrc = 1; +- else +- lrc = checkForLilo(lconfig); +- } +- +- if (!access(eliloConfigType.defaultConfig, F_OK)) { +- econfig = readConfig(eliloConfigType.defaultConfig, +- &eliloConfigType); +- if (!econfig) +- erc = 1; +- else +- erc = checkForElilo(econfig); +- } +- +- if (!access(extlinuxConfigType.defaultConfig, F_OK)) { +- lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType); +- if (!lconfig) +- extrc = 1; +- else +- extrc = checkForExtLinux(lconfig); +- } +- +- +- if (!access(yabootConfigType.defaultConfig, F_OK)) { +- yconfig = readConfig(yabootConfigType.defaultConfig, +- &yabootConfigType); +- if (!yconfig) +- yrc = 1; +- else +- yrc = checkForYaboot(yconfig); +- } +- +- if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 || +- erc == 1) +- return 1; +- +- if (lrc == 2) printf("lilo\n"); +- if (gr2c == 2) printf("grub2\n"); +- if (grc == 2) printf("grub\n"); +- if (extrc == 2) printf("extlinux\n"); +- if (yrc == 2) printf("yaboot\n"); +- if (erc == 2) printf("elilo\n"); + +- return 0; +- } ++ if (!cfi->mbAllowExtraInitRds && extraInitrdCount > 0) { ++ fprintf(stderr, ++ _("grubby: %s doesn't allow multiple initrds\n"), ++ cfi->defaultConfig); ++ return 1; ++ } + +- if (grubConfig == NULL) { +- printf("Could not find bootloader configuration file.\n"); +- exit(1); +- } ++ if (bootloaderProbe) { ++ int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0; ++ struct grubConfig *lconfig, *gconfig, *yconfig, *econfig; ++ ++ const char *grub2config = grub2FindConfig(&grub2ConfigType); ++ if (grub2config) { ++ gconfig = readConfig(grub2config, &grub2ConfigType); ++ if (!gconfig) ++ gr2c = 1; ++ else ++ gr2c = checkForGrub2(gconfig); ++ } + +- config = readConfig(grubConfig, cfi); +- if (!config) return 1; ++ const char *grubconfig = grubFindConfig(&grubConfigType); ++ if (!access(grubconfig, F_OK)) { ++ gconfig = readConfig(grubconfig, &grubConfigType); ++ if (!gconfig) ++ grc = 1; ++ else ++ grc = checkForGrub(gconfig); ++ } + +- if (displayDefault) { +- struct singleLine * line; +- struct singleEntry * entry; +- char * rootspec; ++ if (!access(liloConfigType.defaultConfig, F_OK)) { ++ lconfig = ++ readConfig(liloConfigType.defaultConfig, ++ &liloConfigType); ++ if (!lconfig) ++ lrc = 1; ++ else ++ lrc = checkForLilo(lconfig); ++ } + +- if (config->defaultImage == -1) return 0; +- if (config->defaultImage == DEFAULT_SAVED_GRUB2 && +- cfi->defaultIsSaved) +- config->defaultImage = 0; +- entry = findEntryByIndex(config, config->defaultImage); +- if (!entry) return 0; +- if (!suitableImage(entry, bootPrefix, 0, flags)) return 0; ++ if (!access(eliloConfigType.defaultConfig, F_OK)) { ++ econfig = readConfig(eliloConfigType.defaultConfig, ++ &eliloConfigType); ++ if (!econfig) ++ erc = 1; ++ else ++ erc = checkForElilo(econfig); ++ } + +- line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); +- if (!line) return 0; ++ if (!access(extlinuxConfigType.defaultConfig, F_OK)) { ++ lconfig = ++ readConfig(extlinuxConfigType.defaultConfig, ++ &extlinuxConfigType); ++ if (!lconfig) ++ extrc = 1; ++ else ++ extrc = checkForExtLinux(lconfig); ++ } + +- rootspec = getRootSpecifier(line->elements[1].item); +- printf("%s%s\n", bootPrefix, line->elements[1].item + +- ((rootspec != NULL) ? strlen(rootspec) : 0)); ++ if (!access(yabootConfigType.defaultConfig, F_OK)) { ++ yconfig = readConfig(yabootConfigType.defaultConfig, ++ &yabootConfigType); ++ if (!yconfig) ++ yrc = 1; ++ else ++ yrc = checkForYaboot(yconfig); ++ } + +- return 0; ++ if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ++ || erc == 1) ++ return 1; + +- } else if (displayDefaultTitle) { +- struct singleLine * line; +- struct singleEntry * entry; ++ if (lrc == 2) ++ printf("lilo\n"); ++ if (gr2c == 2) ++ printf("grub2\n"); ++ if (grc == 2) ++ printf("grub\n"); ++ if (extrc == 2) ++ printf("extlinux\n"); ++ if (yrc == 2) ++ printf("yaboot\n"); ++ if (erc == 2) ++ printf("elilo\n"); + +- if (config->defaultImage == -1) +- return 0; +- if (config->defaultImage == DEFAULT_SAVED_GRUB2 && +- cfi->defaultIsSaved) +- config->defaultImage = 0; +- entry = findEntryByIndex(config, config->defaultImage); +- if (!entry) + return 0; ++ } ++ ++ if (grubConfig == NULL) { ++ printf("Could not find bootloader configuration file.\n"); ++ exit(1); ++ } ++ ++ config = readConfig(grubConfig, cfi); ++ if (!config) ++ return 1; ++ ++ if (displayDefault) { ++ struct singleLine *line; ++ struct singleEntry *entry; ++ char *rootspec; ++ ++ if (config->defaultImage == -1) ++ return 0; ++ if (config->defaultImage == DEFAULT_SAVED_GRUB2 && ++ cfi->defaultIsSaved) ++ config->defaultImage = 0; ++ entry = findEntryByIndex(config, config->defaultImage); ++ if (!entry) ++ return 0; ++ if (!suitableImage(entry, bootPrefix, 0, flags)) ++ return 0; ++ ++ line = ++ getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | ++ LT_KERNEL_16, entry->lines); ++ if (!line) ++ return 0; ++ ++ rootspec = getRootSpecifier(line->elements[1].item); ++ printf("%s%s\n", bootPrefix, line->elements[1].item + ++ ((rootspec != NULL) ? strlen(rootspec) : 0)); + +- if (!configureGrub2) { +- char *title; +- line = getLineByType(LT_TITLE, entry->lines); +- if (!line) + return 0; +- title = extractTitle(config, line); +- if (!title) ++ ++ } else if (displayDefaultTitle) { ++ struct singleLine *line; ++ struct singleEntry *entry; ++ ++ if (config->defaultImage == -1) ++ return 0; ++ if (config->defaultImage == DEFAULT_SAVED_GRUB2 && ++ cfi->defaultIsSaved) ++ config->defaultImage = 0; ++ entry = findEntryByIndex(config, config->defaultImage); ++ if (!entry) ++ return 0; ++ ++ if (!configureGrub2) { ++ char *title; ++ line = getLineByType(LT_TITLE, entry->lines); ++ if (!line) ++ return 0; ++ title = extractTitle(config, line); ++ if (!title) ++ return 0; ++ printf("%s\n", title); ++ free(title); ++ } else { ++ char *title; ++ ++ dbgPrintf ++ ("This is GRUB2, default title is embeded in menuentry\n"); ++ line = getLineByType(LT_MENUENTRY, entry->lines); ++ if (!line) ++ return 0; ++ title = grub2ExtractTitle(line); ++ if (title) ++ printf("%s\n", title); ++ } + return 0; +- printf("%s\n", title); +- free(title); +- } else { +- char * title; + +- dbgPrintf("This is GRUB2, default title is embeded in menuentry\n"); +- line = getLineByType(LT_MENUENTRY, entry->lines); +- if (!line) ++ } else if (displayDefaultIndex) { ++ if (config->defaultImage == -1) ++ return 0; ++ if (config->defaultImage == DEFAULT_SAVED_GRUB2 && ++ cfi->defaultIsSaved) ++ config->defaultImage = 0; ++ printf("%i\n", config->defaultImage); + return 0; +- title = grub2ExtractTitle(line); +- if (title) +- printf("%s\n", title); ++ ++ } else if (kernelInfo) ++ return displayInfo(config, kernelInfo, bootPrefix); ++ ++ if (copyDefault) { ++ template = findTemplate(config, bootPrefix, NULL, 0, flags); ++ if (!template) ++ return 1; + } +- return 0; + +- } else if (displayDefaultIndex) { +- if (config->defaultImage == -1) return 0; +- if (config->defaultImage == DEFAULT_SAVED_GRUB2 && +- cfi->defaultIsSaved) +- config->defaultImage = 0; +- printf("%i\n", config->defaultImage); +- return 0; +- +- } else if (kernelInfo) +- return displayInfo(config, kernelInfo, bootPrefix); +- +- if (copyDefault) { +- template = findTemplate(config, bootPrefix, NULL, 0, flags); +- if (!template) return 1; +- } +- +- markRemovedImage(config, removeKernelPath, bootPrefix); +- markRemovedImage(config, removeMBKernel, bootPrefix); +- setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault, +- bootPrefix, flags, defaultIndex); +- setFallbackImage(config, newKernelPath != NULL); +- if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs, +- removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1; +- if (updateKernelPath && newKernelInitrd) { +- if (newMBKernel) { +- if (addMBInitrd(config, newMBKernel, updateKernelPath, ++ markRemovedImage(config, removeKernelPath, bootPrefix); ++ markRemovedImage(config, removeMBKernel, bootPrefix); ++ setDefaultImage(config, newKernelPath != NULL, defaultKernel, ++ makeDefault, bootPrefix, flags, defaultIndex); ++ setFallbackImage(config, newKernelPath != NULL); ++ if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs, ++ removeArgs, newMBKernelArgs, removeMBKernelArgs)) ++ return 1; ++ if (updateKernelPath && newKernelInitrd) { ++ if (newMBKernel) { ++ if (addMBInitrd(config, newMBKernel, updateKernelPath, + bootPrefix, newKernelInitrd, + newKernelTitle)) +- return 1; +- } else { +- if (updateInitrd(config, updateKernelPath, bootPrefix, +- newKernelInitrd, newKernelTitle)) +- return 1; +- } +- } +- if (addNewKernel(config, template, bootPrefix, newKernelPath, +- newKernelTitle, newKernelArgs, newKernelInitrd, +- (const char **)extraInitrds, extraInitrdCount, +- newMBKernel, newMBKernelArgs)) return 1; +- +- +- if (numEntries(config) == 0) { +- fprintf(stderr, _("grubby: doing this would leave no kernel entries. " +- "Not writing out new config.\n")); +- return 1; +- } +- +- if (!outputFile) +- outputFile = (char *)grubConfig; +- +- return writeConfig(config, outputFile, bootPrefix); ++ return 1; ++ } else { ++ if (updateInitrd(config, updateKernelPath, bootPrefix, ++ newKernelInitrd, newKernelTitle)) ++ return 1; ++ } ++ } ++ if (addNewKernel(config, template, bootPrefix, newKernelPath, ++ newKernelTitle, newKernelArgs, newKernelInitrd, ++ (const char **)extraInitrds, extraInitrdCount, ++ newMBKernel, newMBKernelArgs)) ++ return 1; ++ ++ if (numEntries(config) == 0) { ++ fprintf(stderr, ++ _("grubby: doing this would leave no kernel entries. " ++ "Not writing out new config.\n")); ++ return 1; ++ } ++ ++ if (!outputFile) ++ outputFile = (char *)grubConfig; ++ ++ return writeConfig(config, outputFile, bootPrefix); + } +-- +2.4.3 + diff --git a/SOURCES/0046-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch b/SOURCES/0046-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch new file mode 100644 index 0000000..08a32e5 --- /dev/null +++ b/SOURCES/0046-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch @@ -0,0 +1,581 @@ +From 8a3357d1257e5e36648c944ff1e461f0f77c88f4 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 6 Aug 2015 10:07:11 -0400 +Subject: [PATCH 3/3] Make SET_VARIABLE get handled individually in + GetNextLine() + +Resolves: rhbz#1152550 + +Signed-off-by: Peter Jones +--- + .gitignore | 2 + + grubby.c | 118 ++++++++++++++++++++++++++------ + test.sh | 8 +++ + test/grub2.16 | 156 +++++++++++++++++++++++++++++++++++++++++++ + test/results/add/g2-1.16 | 170 +++++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 433 insertions(+), 21 deletions(-) + create mode 100644 test/grub2.16 + create mode 100644 test/results/add/g2-1.16 + +diff --git a/.gitignore b/.gitignore +index e64d3bc..e78a392 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,5 @@ + grubby + version.h + *.o ++core.* ++vgcore.* +diff --git a/grubby.c b/grubby.c +index 53c11a8..04c5bcb 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -75,6 +75,7 @@ struct lineElement { + }; + + enum lineType_e { ++ LT_UNIDENTIFIED = 0, + LT_WHITESPACE = 1 << 0, + LT_TITLE = 1 << 1, + LT_KERNEL = 1 << 2, +@@ -740,6 +741,33 @@ static char *sdupprintf(const char *format, ...) + return buf; + } + ++static inline int ++kwcmp(struct keywordTypes *kw, const char * label, int case_insensitive) ++{ ++ int kwl = strlen(kw->key); ++ int ll = strlen(label); ++ int rc; ++ int (*snc)(const char *s1, const char *s2, size_t n) = ++ case_insensitive ? strncasecmp : strncmp; ++ int (*sc)(const char *s1, const char *s2) = ++ case_insensitive ? strcasecmp : strcmp; ++ ++ rc = snc(kw->key, label, kwl); ++ if (rc) ++ return rc; ++ ++ for (int i = kwl; i < ll; i++) { ++ if (isspace(label[i])) ++ return 0; ++ if (kw->separatorChar && label[i] == kw->separatorChar) ++ return 0; ++ else if (kw->nextChar && label[i] == kw->nextChar) ++ return 0; ++ return sc(kw->key+kwl, label+kwl); ++ } ++ return 0; ++} ++ + static enum lineType_e preferredLineType(enum lineType_e type, + struct configFileInfo *cfi) + { +@@ -805,13 +833,8 @@ static enum lineType_e getTypeByKeyword(char *keyword, + struct configFileInfo *cfi) + { + for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) { +- if (cfi->caseInsensitive) { +- if (!strcasecmp(keyword, kw->key)) +- return kw->type; +- } else { +- if (!strcmp(keyword, kw->key)) +- return kw->type; +- } ++ if (!kwcmp(kw, keyword, cfi->caseInsensitive)) ++ return kw->type; + } + return LT_UNKNOWN; + } +@@ -906,6 +929,7 @@ static int readFile(int fd, char **bufPtr) + + static void lineInit(struct singleLine *line) + { ++ line->type = LT_UNIDENTIFIED; + line->indent = NULL; + line->elements = NULL; + line->numElements = 0; +@@ -987,7 +1011,7 @@ static int lineWrite(FILE * out, struct singleLine *line, + + if (fprintf(out, "%s", line->elements[i].item) == -1) + return -1; +- if (i < line->numElements - 1) ++ if (i < line->numElements - 1 || line->type == LT_SET_VARIABLE) + if (fprintf(out, "%s", line->elements[i].indent) == -1) + return -1; + } +@@ -1042,6 +1066,8 @@ static int getNextLine(char **bufPtr, struct singleLine *line, + break; + chptr++; + } ++ if (line->type == LT_UNIDENTIFIED) ++ line->type = getTypeByKeyword(start, cfi); + element->item = strndup(start, chptr - start); + start = chptr; + +@@ -1105,7 +1131,7 @@ static int getNextLine(char **bufPtr, struct singleLine *line, + line->type = LT_WHITESPACE; + line->numElements = 0; + } +- } else { ++ } else if (line->type == LT_INITRD) { + struct keywordTypes *kw; + + kw = getKeywordByType(line->type, cfi); +@@ -1167,6 +1193,39 @@ static int getNextLine(char **bufPtr, struct singleLine *line, + } + } + } ++ } else if (line->type == LT_SET_VARIABLE) { ++ /* and if it's a "set blah=" we need to split it ++ * yet a third way to avoid rhbz# XXX FIXME :/ ++ */ ++ char *eq; ++ int l; ++ int numElements = line->numElements; ++ struct lineElement *newElements; ++ eq = strchr(line->elements[1].item, '='); ++ if (!eq) ++ return 0; ++ l = eq - line->elements[1].item; ++ if (eq[1] != 0) ++ numElements++; ++ newElements = calloc(numElements,sizeof (*newElements)); ++ memcpy(&newElements[0], &line->elements[0], ++ sizeof (newElements[0])); ++ newElements[1].item = ++ strndup(line->elements[1].item, l); ++ newElements[1].indent = "="; ++ *(eq++) = '\0'; ++ newElements[2].item = strdup(eq); ++ free(line->elements[1].item); ++ if (line->elements[1].indent) ++ newElements[2].indent = line->elements[1].indent; ++ for (int i = 2; i < line->numElements; i++) { ++ newElements[i+1].item = line->elements[i].item; ++ newElements[i+1].indent = ++ line->elements[i].indent; ++ } ++ free(line->elements); ++ line->elements = newElements; ++ line->numElements = numElements; + } + } + +@@ -1272,8 +1331,8 @@ static struct grubConfig *readConfig(const char *inName, + getKeywordByType(LT_DEFAULT, cfi); + if (kwType && line->numElements == 3 + && !strcmp(line->elements[1].item, kwType->key) +- && !is_special_grub2_variable(line->elements[2]. +- item)) { ++ && !is_special_grub2_variable( ++ line->elements[2].item)) { + dbgPrintf("Line sets default config\n"); + cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; + defaultLine = line; +@@ -1529,16 +1588,33 @@ static struct grubConfig *readConfig(const char *inName, + } + } + } else if (cfi->defaultIsVariable) { +- char *value = defaultLine->elements[2].item; +- while (*value && (*value == '"' || *value == '\'' || +- *value == ' ' || *value == '\t')) +- value++; +- cfg->defaultImage = strtol(value, &end, 10); +- while (*end && (*end == '"' || *end == '\'' || +- *end == ' ' || *end == '\t')) +- end++; +- if (*end) +- cfg->defaultImage = -1; ++ if (defaultLine->numElements == 2) { ++ char *value = defaultLine->elements[1].item + 8; ++ while (*value && (*value == '"' || ++ *value == '\'' || ++ *value == ' ' || ++ *value == '\t')) ++ value++; ++ cfg->defaultImage = strtol(value, &end, 10); ++ while (*end && (*end == '"' || *end == '\'' || ++ *end == ' ' || *end == '\t')) ++ end++; ++ if (*end) ++ cfg->defaultImage = -1; ++ } else if (defaultLine->numElements == 3) { ++ char *value = defaultLine->elements[2].item; ++ while (*value && (*value == '"' || ++ *value == '\'' || ++ *value == ' ' || ++ *value == '\t')) ++ value++; ++ cfg->defaultImage = strtol(value, &end, 10); ++ while (*end && (*end == '"' || *end == '\'' || ++ *end == ' ' || *end == '\t')) ++ end++; ++ if (*end) ++ cfg->defaultImage = -1; ++ } + } else if (cfi->defaultSupportSaved && + !strncmp(defaultLine->elements[1].item, "saved", + 5)) { +diff --git a/test.sh b/test.sh +index c2a66e2..9e9be23 100755 +--- a/test.sh ++++ b/test.sh +@@ -542,6 +542,14 @@ if [ "$testgrub2" == "y" ]; then + ;; + esac + ++ # a grub2 add with a "set" of the form: set foo="bar=1,2". bz#1152550 ++ # has this being emitted as: set foo="bar=1,2"=1,2" ++ # which is wrong. ++ grub2Test grub2.16 add/g2-1.16 \ ++ --add-kernel=/boot/vmlinuz-foo \ ++ --copy-default --title 'Red Hat Enterprise Linux Server' \ ++ --args=root=/dev/mapper/foo-- ++ + testing="GRUB2 add initrd" + grub2Test grub2.2 add/g2-1.4 --update-kernel=/boot/new-kernel.img \ + --initrd=/boot/new-initrd --boot-filesystem=/boot/ +diff --git a/test/grub2.16 b/test/grub2.16 +new file mode 100644 +index 0000000..136880a +--- /dev/null ++++ b/test/grub2.16 +@@ -0,0 +1,156 @@ ++# ++# DO NOT EDIT THIS FILE ++# ++# It is automatically generated by grub2-mkconfig using templates ++# from /etc/grub.d and settings from /etc/default/grub ++# ++ ++### BEGIN /etc/grub.d/00_header ### ++set pager=1 ++ ++if [ -s $prefix/grubenv ]; then ++ load_env ++fi ++if [ "${next_entry}" ] ; then ++ set default="${next_entry}" ++ set next_entry= ++ save_env next_entry ++ set boot_once=true ++else ++ set default="${saved_entry}" ++fi ++ ++if [ x"${feature_menuentry_id}" = xy ]; then ++ menuentry_id_option="--id" ++else ++ menuentry_id_option="" ++fi ++ ++export menuentry_id_option ++ ++if [ "${prev_saved_entry}" ]; then ++ set saved_entry="${prev_saved_entry}" ++ save_env saved_entry ++ set prev_saved_entry= ++ save_env prev_saved_entry ++ set boot_once=true ++fi ++ ++function savedefault { ++ if [ -z "${boot_once}" ]; then ++ saved_entry="${chosen}" ++ save_env saved_entry ++ fi ++} ++ ++function load_video { ++ if [ x$feature_all_video_module = xy ]; then ++ insmod all_video ++ else ++ insmod efi_gop ++ insmod efi_uga ++ insmod ieee1275_fb ++ insmod vbe ++ insmod vga ++ insmod video_bochs ++ insmod video_cirrus ++ fi ++} ++ ++serial --speed=115200 ++terminal_input serial console ++terminal_output serial console ++if [ x$feature_timeout_style = xy ] ; then ++ set timeout_style=menu ++ set timeout=5 ++# Fallback normal timeout code in case the timeout_style feature is ++# unavailable. ++else ++ set timeout=5 ++fi ++### END /etc/grub.d/00_header ### ++ ++### BEGIN /etc/grub.d/00_tuned ### ++set tuned_params="isolcpus=1,3" ++### END /etc/grub.d/00_tuned ### ++ ++### BEGIN /etc/grub.d/01_users ### ++if [ -f ${prefix}/user.cfg ]; then ++ source ${prefix}/user.cfg ++ if [ -n ${GRUB2_PASSWORD} ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root ${GRUB2_PASSWORD} ++ fi ++fi ++### END /etc/grub.d/01_users ### ++ ++### BEGIN /etc/grub.d/10_linux ### ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-3.10.0-296.el7.x86_64.img ++} ++menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img ++} ++if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; ++### END /etc/grub.d/10_linux ### ++ ++### BEGIN /etc/grub.d/20_linux_xen ### ++### END /etc/grub.d/20_linux_xen ### ++ ++### BEGIN /etc/grub.d/20_ppc_terminfo ### ++### END /etc/grub.d/20_ppc_terminfo ### ++ ++### BEGIN /etc/grub.d/30_os-prober ### ++### END /etc/grub.d/30_os-prober ### ++ ++### BEGIN /etc/grub.d/40_custom ### ++# This file provides an easy way to add custom menu entries. Simply type the ++# menu entries you want to add after this comment. Be careful not to change ++# the 'exec tail' line above. ++### END /etc/grub.d/40_custom ### ++ ++### BEGIN /etc/grub.d/41_custom ### ++if [ -f ${config_directory}/custom.cfg ]; then ++ source ${config_directory}/custom.cfg ++elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then ++ source $prefix/custom.cfg; ++fi ++### END /etc/grub.d/41_custom ### +diff --git a/test/results/add/g2-1.16 b/test/results/add/g2-1.16 +new file mode 100644 +index 0000000..fc98757 +--- /dev/null ++++ b/test/results/add/g2-1.16 +@@ -0,0 +1,170 @@ ++# ++# DO NOT EDIT THIS FILE ++# ++# It is automatically generated by grub2-mkconfig using templates ++# from /etc/grub.d and settings from /etc/default/grub ++# ++ ++### BEGIN /etc/grub.d/00_header ### ++set pager=1 ++ ++if [ -s $prefix/grubenv ]; then ++ load_env ++fi ++if [ "${next_entry}" ] ; then ++ set default="${next_entry}" ++ set next_entry= ++ save_env next_entry ++ set boot_once=true ++else ++ set default="${saved_entry}" ++fi ++ ++if [ x"${feature_menuentry_id}" = xy ]; then ++ menuentry_id_option="--id" ++else ++ menuentry_id_option="" ++fi ++ ++export menuentry_id_option ++ ++if [ "${prev_saved_entry}" ]; then ++ set saved_entry="${prev_saved_entry}" ++ save_env saved_entry ++ set prev_saved_entry= ++ save_env prev_saved_entry ++ set boot_once=true ++fi ++ ++function savedefault { ++ if [ -z "${boot_once}" ]; then ++ saved_entry="${chosen}" ++ save_env saved_entry ++ fi ++} ++ ++function load_video { ++ if [ x$feature_all_video_module = xy ]; then ++ insmod all_video ++ else ++ insmod efi_gop ++ insmod efi_uga ++ insmod ieee1275_fb ++ insmod vbe ++ insmod vga ++ insmod video_bochs ++ insmod video_cirrus ++ fi ++} ++ ++serial --speed=115200 ++terminal_input serial console ++terminal_output serial console ++if [ x$feature_timeout_style = xy ] ; then ++ set timeout_style=menu ++ set timeout=5 ++# Fallback normal timeout code in case the timeout_style feature is ++# unavailable. ++else ++ set timeout=5 ++fi ++### END /etc/grub.d/00_header ### ++ ++### BEGIN /etc/grub.d/00_tuned ### ++set tuned_params="isolcpus=1,3" ++### END /etc/grub.d/00_tuned ### ++ ++### BEGIN /etc/grub.d/01_users ### ++if [ -f ${prefix}/user.cfg ]; then ++ source ${prefix}/user.cfg ++ if [ -n ${GRUB2_PASSWORD} ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root ${GRUB2_PASSWORD} ++ fi ++fi ++### END /etc/grub.d/01_users ### ++ ++### BEGIN /etc/grub.d/10_linux ### ++menuentry 'Red Hat Enterprise Linux Server' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-foo root=/dev/mapper/foo-- ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-3.10.0-296.el7.x86_64.img ++} ++menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img ++} ++if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; ++### END /etc/grub.d/10_linux ### ++ ++### BEGIN /etc/grub.d/20_linux_xen ### ++### END /etc/grub.d/20_linux_xen ### ++ ++### BEGIN /etc/grub.d/20_ppc_terminfo ### ++### END /etc/grub.d/20_ppc_terminfo ### ++ ++### BEGIN /etc/grub.d/30_os-prober ### ++### END /etc/grub.d/30_os-prober ### ++ ++### BEGIN /etc/grub.d/40_custom ### ++# This file provides an easy way to add custom menu entries. Simply type the ++# menu entries you want to add after this comment. Be careful not to change ++# the 'exec tail' line above. ++### END /etc/grub.d/40_custom ### ++ ++### BEGIN /etc/grub.d/41_custom ### ++if [ -f ${config_directory}/custom.cfg ]; then ++ source ${config_directory}/custom.cfg ++elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then ++ source $prefix/custom.cfg; ++fi ++### END /etc/grub.d/41_custom ### +-- +2.4.3 + diff --git a/SOURCES/0047-Specify-bootloader-directory-in-the-test-case-for-11.patch b/SOURCES/0047-Specify-bootloader-directory-in-the-test-case-for-11.patch new file mode 100644 index 0000000..79639f8 --- /dev/null +++ b/SOURCES/0047-Specify-bootloader-directory-in-the-test-case-for-11.patch @@ -0,0 +1,30 @@ +From 2793c9305a1092c03d04a5fe0fa3a56811039447 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 1 Sep 2015 11:02:07 -0400 +Subject: [PATCH] Specify bootloader directory in the test case for 1152550. + +Because otherwise it blows up when built in mock without /boot mounted. + +Related: rhbz#1152550 + +Signed-off-by: Peter Jones +--- + test.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test.sh b/test.sh +index cd2d870..ba466a5 100755 +--- a/test.sh ++++ b/test.sh +@@ -547,7 +547,7 @@ if [ "$testgrub2" == "y" ]; then + # has this being emitted as: set foo="bar=1,2"=1,2" + # which is wrong. + grub2Test grub2.16 add/g2-1.16 \ +- --add-kernel=/boot/vmlinuz-foo \ ++ --boot-filesystem=/boot --add-kernel=/boot/vmlinuz-foo \ + --copy-default --title 'Red Hat Enterprise Linux Server' \ + --args=root=/dev/mapper/foo-- + +-- +2.4.3 + diff --git a/SOURCES/0048-Fix-some-coverity-concerns.patch b/SOURCES/0048-Fix-some-coverity-concerns.patch new file mode 100644 index 0000000..a00bdde --- /dev/null +++ b/SOURCES/0048-Fix-some-coverity-concerns.patch @@ -0,0 +1,613 @@ +From 916d5770b5c8fb87503a99f98c13a5232a7dafbf Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 10 Sep 2015 10:13:15 -0400 +Subject: [PATCH] Fix some coverity concerns... + +While checking on coverity's concern with kwcmp() having a loop it +really didn't need, I discovered another problem with the fix here that +made spaces not work right in grub2 variable assignment. So here's a +new version of the fix, and yet another test case. + +Resolves: rhbz#1152550 + +Signed-off-by: Peter Jones +--- + grubby.c | 204 ++++++++++++++++++++++++++++++++++++----------- + test.sh | 6 ++ + test/grub2.17 | 156 ++++++++++++++++++++++++++++++++++++ + test/results/add/g2-1.17 | 170 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 490 insertions(+), 46 deletions(-) + create mode 100644 test/grub2.17 + create mode 100644 test/results/add/g2-1.17 + +diff --git a/grubby.c b/grubby.c +index d66c1c5..2a6eedb 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -751,28 +751,30 @@ static char *sdupprintf(const char *format, ...) + static inline int + kwcmp(struct keywordTypes *kw, const char * label, int case_insensitive) + { +- int kwl = strlen(kw->key); +- int ll = strlen(label); +- int rc; +- int (*snc)(const char *s1, const char *s2, size_t n) = +- case_insensitive ? strncasecmp : strncmp; +- int (*sc)(const char *s1, const char *s2) = +- case_insensitive ? strcasecmp : strcmp; +- +- rc = snc(kw->key, label, kwl); +- if (rc) +- return rc; +- +- for (int i = kwl; i < ll; i++) { +- if (isspace(label[i])) +- return 0; +- if (kw->separatorChar && label[i] == kw->separatorChar) +- return 0; +- else if (kw->nextChar && label[i] == kw->nextChar) +- return 0; +- return sc(kw->key+kwl, label+kwl); +- } +- return 0; ++ int kwl = strlen(kw->key); ++ int ll = strlen(label); ++ int rc; ++ int (*snc)(const char *s1, const char *s2, size_t n) = ++ case_insensitive ? strncasecmp : strncmp; ++ int (*sc)(const char *s1, const char *s2) = ++ case_insensitive ? strcasecmp : strcmp; ++ ++ if (kwl > ll) ++ return ll - kwl; ++ ++ rc = snc(kw->key, label, kwl); ++ if (rc) ++ return rc; ++ ++ if (!label[kwl]) ++ return 0; ++ if (isspace(label[kwl])) ++ return 0; ++ if (kw->separatorChar && label[kwl] == kw->separatorChar) ++ return 0; ++ if (kw->nextChar && label[kwl] == kw->nextChar) ++ return 0; ++ return sc(kw->key+kwl, label+kwl); + } + + static enum lineType_e preferredLineType(enum lineType_e type, +@@ -1034,6 +1036,123 @@ static int lineWrite(FILE * out, struct singleLine *line, + return 0; + } + ++static int mergeElements(struct singleLine *line, int left, int right) ++{ ++ struct lineElement *elements = alloca(sizeof (line->elements[0]) * ++ line->numElements); ++ int i, j; ++ size_t itemsize = 0; ++ size_t newNumElements = 0; ++ char *newitem; ++ char *newindent = NULL; ++ ++ if (right >= line->numElements) ++ right = line->numElements - 1; ++ ++ if (!elements) ++ return -1; ++ for (i = 0; i < left; i++) { ++ elements[i] = line->elements[i]; ++ newNumElements++; ++ } ++ for (; i <= right; i++) { ++ itemsize += strlen(line->elements[i].item); ++ if (line->elements[i].indent && line->elements[i].indent[0]) { ++ if (i != right) ++ itemsize += strlen(line->elements[i].indent); ++ } ++ } ++ newitem = calloc (itemsize+1, 1); ++ if (!newitem) ++ return -1; ++ for (i = left; i <= right; i++) { ++ strcat(newitem, line->elements[i].item); ++ if (line->elements[i].indent) { ++ if (i != right) { ++ strcat(newitem, line->elements[i].indent); ++ free(line->elements[i].indent); ++ } else { ++ newindent = line->elements[i].indent; ++ } ++ } else { ++ newindent = strdup(""); ++ } ++ } ++ newNumElements++; ++ elements[left].item = newitem; ++ elements[left].indent = newindent; ++ if (left+1 < line->numElements && right+1 < line->numElements) { ++ for (j = left+1, i = right+1; i < line->numElements; i++) { ++ elements[j++] = line->elements[i]; ++ newNumElements++; ++ } ++ } ++ memcpy(line->elements, elements, ++ sizeof (line->elements[i]) * newNumElements); ++ line->numElements = newNumElements; ++ return 0; ++} ++ ++static int emptyElement(struct lineElement *element) ++{ ++ if (element->item && strlen(element->item) > 0) ++ return 0; ++ if (element->indent && strlen(element->indent) > 0) ++ return 0; ++ return 1; ++} ++ ++static int splitElement(struct singleLine *line, int element, int splitchar) ++{ ++ struct lineElement split[2] = {{0,0},{0,0}}; ++ struct lineElement *elements = NULL; ++ int saved_errno; ++ int i, j; ++ ++ elements = calloc(line->numElements + 1, sizeof (line->elements[0])); ++ if (!elements) ++ return -1; ++ ++ split[0].item = strndup(line->elements[element].item, splitchar); ++ if (!split[0].item) ++ goto err; ++ split[0].indent = strndup(&line->elements[element].item[splitchar], 1); ++ if (!split[0].indent) ++ goto err; ++ split[1].item = strdup(&line->elements[element].item[splitchar+1]); ++ if (!split[1].item) ++ goto err; ++ split[1].indent = line->elements[element].indent; ++ ++ for (i = j = 0; i < line->numElements; i++) { ++ if (i != element) { ++ memcpy(&elements[j++], &line->elements[i], ++ sizeof(line->elements[i])); ++ } else { ++ memcpy(&elements[j++], &split[0], sizeof(split[0])); ++ memcpy(&elements[j++], &split[1], sizeof(split[1])); ++ free(line->elements[i].item); ++ } ++ } ++ free(line->elements); ++ line->elements = elements; ++ line->numElements++; ++ ++ return 0; ++err: ++ saved_errno = errno; ++ if (split[0].item) ++ free(split[0].item); ++ if (split[0].indent) ++ free(split[0].indent); ++ if (split[1].item) ++ free(split[1].item); ++ if (elements) ++ free(elements); ++ errno = saved_errno; ++ return -1; ++} ++ + /* we've guaranteed that the buffer ends w/ \n\0 */ + static int getNextLine(char **bufPtr, struct singleLine *line, + struct configFileInfo *cfi) +@@ -1208,34 +1327,27 @@ static int getNextLine(char **bufPtr, struct singleLine *line, + * yet a third way to avoid rhbz# XXX FIXME :/ + */ + char *eq; +- int l; +- int numElements = line->numElements; +- struct lineElement *newElements; ++ int rc; ++ rc = mergeElements(line, 2, line->numElements); ++ if (rc < 0) ++ return rc; + eq = strchr(line->elements[1].item, '='); + if (!eq) + return 0; +- l = eq - line->elements[1].item; +- if (eq[1] != 0) +- numElements++; +- newElements = calloc(numElements,sizeof (*newElements)); +- memcpy(&newElements[0], &line->elements[0], +- sizeof (newElements[0])); +- newElements[1].item = +- strndup(line->elements[1].item, l); +- newElements[1].indent = "="; +- *(eq++) = '\0'; +- newElements[2].item = strdup(eq); +- free(line->elements[1].item); +- if (line->elements[1].indent) +- newElements[2].indent = line->elements[1].indent; +- for (int i = 2; i < line->numElements; i++) { +- newElements[i+1].item = line->elements[i].item; +- newElements[i+1].indent = +- line->elements[i].indent; ++ rc = splitElement(line, 1, eq-line->elements[1].item); ++ if (rc < 0) ++ return rc; ++ /* now make sure we haven't got any bogus elements at ++ * the end that don't mean anything. ++ */ ++ while (line->numElements > 1 && ++ emptyElement( ++ &line->elements[line->numElements-1])) { ++ rc = mergeElements(line, line->numElements-2, ++ line->numElements-1); ++ if (rc < 0) ++ return rc; + } +- free(line->elements); +- line->elements = newElements; +- line->numElements = numElements; + } + } + +diff --git a/test.sh b/test.sh +index ba466a5..d488333 100755 +--- a/test.sh ++++ b/test.sh +@@ -551,6 +551,12 @@ if [ "$testgrub2" == "y" ]; then + --copy-default --title 'Red Hat Enterprise Linux Server' \ + --args=root=/dev/mapper/foo-- + ++ # the same, but for: set foo = " bar=1,2 " ++ grub2Test grub2.17 add/g2-1.17 \ ++ --boot-filesystem=/boot --add-kernel=/boot/vmlinuz-foo \ ++ --copy-default --title 'Red Hat Enterprise Linux Server' \ ++ --args=root=/dev/mapper/foo-- ++ + testing="GRUB2 add initrd" + grub2Test grub2.2 add/g2-1.4 --update-kernel=/boot/new-kernel.img \ + --initrd=/boot/new-initrd --boot-filesystem=/boot/ +diff --git a/test/grub2.17 b/test/grub2.17 +new file mode 100644 +index 0000000..bd8c9c5 +--- /dev/null ++++ b/test/grub2.17 +@@ -0,0 +1,156 @@ ++# ++# DO NOT EDIT THIS FILE ++# ++# It is automatically generated by grub2-mkconfig using templates ++# from /etc/grub.d and settings from /etc/default/grub ++# ++ ++### BEGIN /etc/grub.d/00_header ### ++set pager=1 ++ ++if [ -s $prefix/grubenv ]; then ++ load_env ++fi ++if [ "${next_entry}" ] ; then ++ set default="${next_entry}" ++ set next_entry= ++ save_env next_entry ++ set boot_once=true ++else ++ set default="${saved_entry}" ++fi ++ ++if [ x"${feature_menuentry_id}" = xy ]; then ++ menuentry_id_option="--id" ++else ++ menuentry_id_option="" ++fi ++ ++export menuentry_id_option ++ ++if [ "${prev_saved_entry}" ]; then ++ set saved_entry="${prev_saved_entry}" ++ save_env saved_entry ++ set prev_saved_entry= ++ save_env prev_saved_entry ++ set boot_once=true ++fi ++ ++function savedefault { ++ if [ -z "${boot_once}" ]; then ++ saved_entry="${chosen}" ++ save_env saved_entry ++ fi ++} ++ ++function load_video { ++ if [ x$feature_all_video_module = xy ]; then ++ insmod all_video ++ else ++ insmod efi_gop ++ insmod efi_uga ++ insmod ieee1275_fb ++ insmod vbe ++ insmod vga ++ insmod video_bochs ++ insmod video_cirrus ++ fi ++} ++ ++serial --speed=115200 ++terminal_input serial console ++terminal_output serial console ++if [ x$feature_timeout_style = xy ] ; then ++ set timeout_style=menu ++ set timeout=5 ++# Fallback normal timeout code in case the timeout_style feature is ++# unavailable. ++else ++ set timeout=5 ++fi ++### END /etc/grub.d/00_header ### ++ ++### BEGIN /etc/grub.d/00_tuned ### ++set tuned_params= " isolcpus=1,3 " ++### END /etc/grub.d/00_tuned ### ++ ++### BEGIN /etc/grub.d/01_users ### ++if [ -f ${prefix}/user.cfg ]; then ++ source ${prefix}/user.cfg ++ if [ -n ${GRUB2_PASSWORD} ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root ${GRUB2_PASSWORD} ++ fi ++fi ++### END /etc/grub.d/01_users ### ++ ++### BEGIN /etc/grub.d/10_linux ### ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-3.10.0-296.el7.x86_64.img ++} ++menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img ++} ++if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; ++### END /etc/grub.d/10_linux ### ++ ++### BEGIN /etc/grub.d/20_linux_xen ### ++### END /etc/grub.d/20_linux_xen ### ++ ++### BEGIN /etc/grub.d/20_ppc_terminfo ### ++### END /etc/grub.d/20_ppc_terminfo ### ++ ++### BEGIN /etc/grub.d/30_os-prober ### ++### END /etc/grub.d/30_os-prober ### ++ ++### BEGIN /etc/grub.d/40_custom ### ++# This file provides an easy way to add custom menu entries. Simply type the ++# menu entries you want to add after this comment. Be careful not to change ++# the 'exec tail' line above. ++### END /etc/grub.d/40_custom ### ++ ++### BEGIN /etc/grub.d/41_custom ### ++if [ -f ${config_directory}/custom.cfg ]; then ++ source ${config_directory}/custom.cfg ++elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then ++ source $prefix/custom.cfg; ++fi ++### END /etc/grub.d/41_custom ### +diff --git a/test/results/add/g2-1.17 b/test/results/add/g2-1.17 +new file mode 100644 +index 0000000..afb151d +--- /dev/null ++++ b/test/results/add/g2-1.17 +@@ -0,0 +1,170 @@ ++# ++# DO NOT EDIT THIS FILE ++# ++# It is automatically generated by grub2-mkconfig using templates ++# from /etc/grub.d and settings from /etc/default/grub ++# ++ ++### BEGIN /etc/grub.d/00_header ### ++set pager=1 ++ ++if [ -s $prefix/grubenv ]; then ++ load_env ++fi ++if [ "${next_entry}" ] ; then ++ set default="${next_entry}" ++ set next_entry= ++ save_env next_entry ++ set boot_once=true ++else ++ set default="${saved_entry}" ++fi ++ ++if [ x"${feature_menuentry_id}" = xy ]; then ++ menuentry_id_option="--id" ++else ++ menuentry_id_option="" ++fi ++ ++export menuentry_id_option ++ ++if [ "${prev_saved_entry}" ]; then ++ set saved_entry="${prev_saved_entry}" ++ save_env saved_entry ++ set prev_saved_entry= ++ save_env prev_saved_entry ++ set boot_once=true ++fi ++ ++function savedefault { ++ if [ -z "${boot_once}" ]; then ++ saved_entry="${chosen}" ++ save_env saved_entry ++ fi ++} ++ ++function load_video { ++ if [ x$feature_all_video_module = xy ]; then ++ insmod all_video ++ else ++ insmod efi_gop ++ insmod efi_uga ++ insmod ieee1275_fb ++ insmod vbe ++ insmod vga ++ insmod video_bochs ++ insmod video_cirrus ++ fi ++} ++ ++serial --speed=115200 ++terminal_input serial console ++terminal_output serial console ++if [ x$feature_timeout_style = xy ] ; then ++ set timeout_style=menu ++ set timeout=5 ++# Fallback normal timeout code in case the timeout_style feature is ++# unavailable. ++else ++ set timeout=5 ++fi ++### END /etc/grub.d/00_header ### ++ ++### BEGIN /etc/grub.d/00_tuned ### ++set tuned_params= " isolcpus=1,3 " ++### END /etc/grub.d/00_tuned ### ++ ++### BEGIN /etc/grub.d/01_users ### ++if [ -f ${prefix}/user.cfg ]; then ++ source ${prefix}/user.cfg ++ if [ -n ${GRUB2_PASSWORD} ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root ${GRUB2_PASSWORD} ++ fi ++fi ++### END /etc/grub.d/01_users ### ++ ++### BEGIN /etc/grub.d/10_linux ### ++menuentry 'Red Hat Enterprise Linux Server' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-foo root=/dev/mapper/foo-- ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-3.10.0-296.el7.x86_64.img ++} ++menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' { ++ load_video ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' cae02b39-f239-4d26-9032-674d261c93d8 ++ else ++ search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8 ++ fi ++ linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81 $tuned_params ++ initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img ++} ++if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi; ++### END /etc/grub.d/10_linux ### ++ ++### BEGIN /etc/grub.d/20_linux_xen ### ++### END /etc/grub.d/20_linux_xen ### ++ ++### BEGIN /etc/grub.d/20_ppc_terminfo ### ++### END /etc/grub.d/20_ppc_terminfo ### ++ ++### BEGIN /etc/grub.d/30_os-prober ### ++### END /etc/grub.d/30_os-prober ### ++ ++### BEGIN /etc/grub.d/40_custom ### ++# This file provides an easy way to add custom menu entries. Simply type the ++# menu entries you want to add after this comment. Be careful not to change ++# the 'exec tail' line above. ++### END /etc/grub.d/40_custom ### ++ ++### BEGIN /etc/grub.d/41_custom ### ++if [ -f ${config_directory}/custom.cfg ]; then ++ source ${config_directory}/custom.cfg ++elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then ++ source $prefix/custom.cfg; ++fi ++### END /etc/grub.d/41_custom ### +-- +2.4.3 + diff --git a/SOURCES/0049-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch b/SOURCES/0049-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch new file mode 100644 index 0000000..4e31618 --- /dev/null +++ b/SOURCES/0049-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch @@ -0,0 +1,123 @@ +From b9a37e249bf279ceb0b63ad4676f03d11796cfc9 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 26 Oct 2015 14:22:39 -0400 +Subject: [PATCH] Always do the "rungrubby --debug" after the normal kernel on + install. + +This way the during an update, the right kernel is picked as "default" +for the command line arguments. + +Related: rhbz#1212128 + +Signed-off-by: Peter Jones +--- + new-kernel-pkg | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/new-kernel-pkg b/new-kernel-pkg +index 9f56c47..9574dbb 100755 +--- a/new-kernel-pkg ++++ b/new-kernel-pkg +@@ -243,8 +243,8 @@ install() { + --args=\"root=$rootdevice $kernargs \$debugargs\" \ + --remove-kernel=\"TITLE=$title\$debugtitle\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} $makedefault ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby for grub 0.97" + fi +@@ -257,8 +257,8 @@ install() { + ${mbargs:+--mbargs=\"$mbargs\"} \ + --args=\"root=$rootdevice $kernargs \$debugargs\" \ + --remove-kernel=\"TITLE=$title\$debugtitle\"" +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} $makedefault ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby for grub 2" + fi +@@ -272,8 +272,8 @@ install() { + ${mbargs:+--mbargs=\"$mbargs\"} \ + --args=\"root=$rootdevice $kernargs \$debugargs\" \ + --remove-kernel=\"TITLE=$title\$debugtitle\"" +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} $makedefault ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby for grub 2 with UEFI" + fi +@@ -288,8 +288,8 @@ install() { + --args=\"root=$rootdevice $kernargs \$debugargs\" \ + --remove-kernel=\"TITLE=$version\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} $makedefault ++ rungrubby --debug ${ARGS} + if [ -n "$runLilo" ]; then + [ -n "$verbose" ] && echo "running $lilo" + if [ ! -x $lilo ] ; then +@@ -313,8 +313,8 @@ install() { + --args=\"root=$rootdevice $kernargs \$debugargs\" \ + --remove-kernel=\"TITLE=$title\$debugtitle\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} $makedefault ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby for extlinux" + fi +@@ -480,8 +480,8 @@ update() { + ${mbkernel:+--add-multiboot=\"$mbkernel\"} \ + --title=\"$title\$debugtitle\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby" + fi +@@ -493,8 +493,8 @@ update() { + ${removeargs:+--remove-args=\"$removeargs\"} \ + --title=\"$title\$debugtitle\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby" + fi +@@ -506,8 +506,8 @@ update() { + ${removeargs:+--remove-args=\"$removeargs\"} \ + --title=\"$title\$debugtitle\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby" + fi +@@ -519,8 +519,8 @@ update() { + ${removeargs:+--remove-args=\"$removeargs\"} \ + --title=\"$title\$debugtitle\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} ++ rungrubby --debug ${ARGS} + + if [ -n "$runLilo" ]; then + [ -n "$verbose" ] && echo "running $lilo" +@@ -571,8 +571,8 @@ update() { + ${removeargs:+--remove-args=\"$removeargs\"} \ + --title=\"$title\$debugtitle\"" + +- rungrubby --debug ${ARGS} + rungrubby ${ARGS} ++ rungrubby --debug ${ARGS} + else + [ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby" + fi +-- +2.5.0 + diff --git a/SOURCES/0050-grubby-add-set-index-to-specify-which-position-to-ad.patch b/SOURCES/0050-grubby-add-set-index-to-specify-which-position-to-ad.patch new file mode 100644 index 0000000..8eba68e --- /dev/null +++ b/SOURCES/0050-grubby-add-set-index-to-specify-which-position-to-ad.patch @@ -0,0 +1,297 @@ +From ddf482232a47f5d2db9b3d40d89ee4094a6ac936 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 22 Jun 2016 14:07:49 -0400 +Subject: [PATCH 50/55] grubby: add --set-index to specify which position to + add new entries as + +This adds an option, "--set-index N", to grubby, and will cause creation +of any new entry to be at a particular zero-indexed position in the +resulting configuration file. + +Related: rhbz#1285601 + +Signed-off-by: Peter Jones +--- + .gitignore | 1 + + grubby.8 | 10 +++++++--- + grubby.c | 26 +++++++++++++++++++++----- + test.sh | 14 ++++++++++++++ + test/grub.15 | 19 +++++++++++++++++++ + test/results/add/g1.10 | 22 ++++++++++++++++++++++ + test/results/add/g1.17 | 19 +++++++++++++++++++ + test/results/add/g1.8 | 22 ++++++++++++++++++++++ + test/results/add/g1.9 | 22 ++++++++++++++++++++++ + 9 files changed, 147 insertions(+), 8 deletions(-) + create mode 100644 test/grub.15 + create mode 100644 test/results/add/g1.10 + create mode 100644 test/results/add/g1.17 + create mode 100644 test/results/add/g1.8 + create mode 100644 test/results/add/g1.9 + +diff --git a/.gitignore b/.gitignore +index e78a392..1c00ff7 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -3,3 +3,4 @@ version.h + *.o + core.* + vgcore.* ++*.tar.* +diff --git a/grubby.8 b/grubby.8 +index 85e22c5..b2a5447 100644 +--- a/grubby.8 ++++ b/grubby.8 +@@ -8,10 +8,10 @@ grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl + [--bootloader-probe] [--config-file \fIpath\fR] [--copy-default] + [--debug] [--default-kernel] [--default-index] [--default-title] + [--grub] [--lilo] [--yaboot] [--silo] [--zipl] +- [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR] +- [--make-default] [-o path] [--version] ++ [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR] ++ [--make-default] [-o path] [--version] [--set-entry=\fIentry-index\fR] + [--remove-kernel=\fIkernel-path\fR] [--remove-args=\fIargs\fR] +- [--set-default=\fIkernel-path\fR] [--set-default-index=\fientry-index\fR] ++ [--set-default=\fIkernel-path\fR] [--set-default-index=\fIentry-index\fR] + [--title=entry-title] [--add-multiboot=\fImultiboot-path\fR] + [--mbargs=\fIargs\fR] [--remove-multiboot=\fImultiboot-path\fR] + [--remove-mbargs=\fIargs\fR] +@@ -48,6 +48,10 @@ with that title are used. + Add a new boot entry for the kernel located at \fIkernel-path\fR. + + .TP ++\fB-\-set-entry\fR=\fIentry-index\fR ++Set the position at which to add a new entry created with \fB-\-add-kernel\fR. ++ ++.TP + \fB-\-args\fR=\fIkernel-args\fR + When a new kernel is added, this specifies the command line arguments + which should be passed to the kernel by default (note they are merged +diff --git a/grubby.c b/grubby.c +index ad2b662..0c260f2 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -4286,9 +4286,10 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template, + const char *newKernelPath, const char *newKernelTitle, + const char *newKernelArgs, const char *newKernelInitrd, + const char **extraInitrds, int extraInitrdCount, +- const char *newMBKernel, const char *newMBKernelArgs) ++ const char *newMBKernel, const char *newMBKernelArgs ++ int newIndex) + { +- struct singleEntry *new; ++ struct singleEntry *new, *entry, *prev = NULL; + struct singleLine *newLine = NULL, *tmplLine = NULL, *masterLine = NULL; + int needs; + char *chptr; +@@ -4318,9 +4319,20 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template, + new = malloc(sizeof(*new)); + new->skip = 0; + new->multiboot = 0; +- new->next = config->entries; + new->lines = NULL; +- config->entries = new; ++ entry = config->entries; ++ for (unsigned int i = 0; i < newIndex; i++) { ++ if (!entry) ++ break; ++ prev = entry; ++ entry = entry->next; ++ } ++ new->next = entry; ++ ++ if (prev) ++ prev->next = new; ++ else ++ config->entries = new; + + /* copy/update from the template */ + needs = NEED_KERNEL | NEED_TITLE; +@@ -4771,6 +4783,7 @@ int main(int argc, const char **argv) + char *newKernelVersion = NULL; + char *newMBKernel = NULL; + char *newMBKernelArgs = NULL; ++ int newIndex = 0; + char *removeMBKernelArgs = NULL; + char *removeMBKernel = NULL; + char *bootPrefix = NULL; +@@ -4873,6 +4886,9 @@ int main(int argc, const char **argv) + {"set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0, + _("make the given entry index the default entry"), + _("entry-index")}, ++ {"set-index", 0, POPT_ARG_INT, &newIndex, 0, ++ _("use the given index when creating a new entry"), ++ _("entry-index")}, + {"silo", 0, POPT_ARG_NONE, &configureSilo, 0, + _("configure silo bootloader")}, + {"title", 0, POPT_ARG_STRING, &newKernelTitle, 0, +@@ -5289,7 +5305,7 @@ int main(int argc, const char **argv) + if (addNewKernel(config, template, bootPrefix, newKernelPath, + newKernelTitle, newKernelArgs, newKernelInitrd, + (const char **)extraInitrds, extraInitrdCount, +- newMBKernel, newMBKernelArgs)) ++ newMBKernel, newMBKernelArgs, newIndex)) + return 1; + + if (numEntries(config) == 0) { +diff --git a/test.sh b/test.sh +index b90798c..9ac0ec9 100755 +--- a/test.sh ++++ b/test.sh +@@ -485,6 +485,20 @@ grubTest grub.8 add/g8.2 --add-kernel=/boot/new-kernel.img --title='title' \ + grubTest grub.11 add/g11.1 --add-kernel=/boot/new-kernel.img --title='title' \ + --initrd=/boot/new-initrd --boot-filesystem=/boot --copy-default \ + --args='console=tty0 console=ttyS1,9600n81 single' ++grubTest grub.1 add/g1.1 --add-kernel=/boot/new-kernel.img --title='title' \ ++ --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 0 ++grubTest grub.1 add/g1.17 --add-kernel=/boot/new-kernel.img --title='title' \ ++ --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 1 ++grubTest grub.1 add/g1.17 --add-kernel=/boot/new-kernel.img --title='title' \ ++ --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 2 ++grubTest grub.15 add/g1.10 --add-kernel=/boot/new-kernel.img --title='title' \ ++ --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 0 ++grubTest grub.15 add/g1.8 --add-kernel=/boot/new-kernel.img --title='title' \ ++ --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 1 ++grubTest grub.15 add/g1.9 --add-kernel=/boot/new-kernel.img --title='title' \ ++ --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 2 ++grubTest grub.15 add/g1.9 --add-kernel=/boot/new-kernel.img --title='title' \ ++ --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 5 + + testgrub2=n + ARCH=$(uname -m | sed s,i[3456789]86,ia32,) +diff --git a/test/grub.15 b/test/grub.15 +new file mode 100644 +index 0000000..e1c5f8a +--- /dev/null ++++ b/test/grub.15 +@@ -0,0 +1,19 @@ ++# grub.conf generated by anaconda ++# ++# Note that you do not have to rerun grub after making changes to this file ++# NOTICE: You have a /boot partition. This means that ++# all kernel and initrd paths are relative to /boot/, eg. ++# root (hd0,0) ++# kernel /vmlinuz-version ro root=/dev/sda1 ++# initrd /initrd-version.img ++#boot=/dev/hda ++default=1 ++timeout=10 ++splashimage=(hd0,0)/grub/splash.xpm.gz ++title Red Hat Linux (2.4.7-2) ++ root (hd0,0) ++ kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1 ++ initrd /initrd-2.4.7-2.img ++title zonk ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd +diff --git a/test/results/add/g1.10 b/test/results/add/g1.10 +new file mode 100644 +index 0000000..dcdd8a8 +--- /dev/null ++++ b/test/results/add/g1.10 +@@ -0,0 +1,22 @@ ++# grub.conf generated by anaconda ++# ++# Note that you do not have to rerun grub after making changes to this file ++# NOTICE: You have a /boot partition. This means that ++# all kernel and initrd paths are relative to /boot/, eg. ++# root (hd0,0) ++# kernel /vmlinuz-version ro root=/dev/sda1 ++# initrd /initrd-version.img ++#boot=/dev/hda ++default=2 ++timeout=10 ++splashimage=(hd0,0)/grub/splash.xpm.gz ++title title ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd ++title Red Hat Linux (2.4.7-2) ++ root (hd0,0) ++ kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1 ++ initrd /initrd-2.4.7-2.img ++title zonk ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd +diff --git a/test/results/add/g1.17 b/test/results/add/g1.17 +new file mode 100644 +index 0000000..6a38822 +--- /dev/null ++++ b/test/results/add/g1.17 +@@ -0,0 +1,19 @@ ++# grub.conf generated by anaconda ++# ++# Note that you do not have to rerun grub after making changes to this file ++# NOTICE: You have a /boot partition. This means that ++# all kernel and initrd paths are relative to /boot/, eg. ++# root (hd0,0) ++# kernel /vmlinuz-version ro root=/dev/sda1 ++# initrd /initrd-version.img ++#boot=/dev/hda ++default=1 ++timeout=10 ++splashimage=(hd0,0)/grub/splash.xpm.gz ++title Red Hat Linux (2.4.7-2) ++ root (hd0,0) ++ kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1 ++ initrd /initrd-2.4.7-2.img ++title title ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd +diff --git a/test/results/add/g1.8 b/test/results/add/g1.8 +new file mode 100644 +index 0000000..5893a2f +--- /dev/null ++++ b/test/results/add/g1.8 +@@ -0,0 +1,22 @@ ++# grub.conf generated by anaconda ++# ++# Note that you do not have to rerun grub after making changes to this file ++# NOTICE: You have a /boot partition. This means that ++# all kernel and initrd paths are relative to /boot/, eg. ++# root (hd0,0) ++# kernel /vmlinuz-version ro root=/dev/sda1 ++# initrd /initrd-version.img ++#boot=/dev/hda ++default=2 ++timeout=10 ++splashimage=(hd0,0)/grub/splash.xpm.gz ++title Red Hat Linux (2.4.7-2) ++ root (hd0,0) ++ kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1 ++ initrd /initrd-2.4.7-2.img ++title title ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd ++title zonk ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd +diff --git a/test/results/add/g1.9 b/test/results/add/g1.9 +new file mode 100644 +index 0000000..310623d +--- /dev/null ++++ b/test/results/add/g1.9 +@@ -0,0 +1,22 @@ ++# grub.conf generated by anaconda ++# ++# Note that you do not have to rerun grub after making changes to this file ++# NOTICE: You have a /boot partition. This means that ++# all kernel and initrd paths are relative to /boot/, eg. ++# root (hd0,0) ++# kernel /vmlinuz-version ro root=/dev/sda1 ++# initrd /initrd-version.img ++#boot=/dev/hda ++default=2 ++timeout=10 ++splashimage=(hd0,0)/grub/splash.xpm.gz ++title Red Hat Linux (2.4.7-2) ++ root (hd0,0) ++ kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1 ++ initrd /initrd-2.4.7-2.img ++title zonk ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd ++title title ++ kernel /boot/new-kernel.img ++ initrd /boot/new-initrd +-- +2.5.5 + diff --git a/SOURCES/0051-Fix-thinko-on-set-index-naming.patch b/SOURCES/0051-Fix-thinko-on-set-index-naming.patch new file mode 100644 index 0000000..e6f163d --- /dev/null +++ b/SOURCES/0051-Fix-thinko-on-set-index-naming.patch @@ -0,0 +1,37 @@ +From 694e8328e37d0f71a4e535b36c6bd1a937956cc0 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 23 Jun 2016 14:45:35 -0400 +Subject: [PATCH 51/55] Fix thinko on --set-index naming. + +Related: rhbz#1285601 + +Signed-off-by: Peter Jones +--- + grubby.8 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grubby.8 b/grubby.8 +index b2a5447..709a539 100644 +--- a/grubby.8 ++++ b/grubby.8 +@@ -9,7 +9,7 @@ grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl + [--debug] [--default-kernel] [--default-index] [--default-title] + [--grub] [--lilo] [--yaboot] [--silo] [--zipl] + [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR] +- [--make-default] [-o path] [--version] [--set-entry=\fIentry-index\fR] ++ [--make-default] [-o path] [--version] [--set-index=\fIentry-index\fR] + [--remove-kernel=\fIkernel-path\fR] [--remove-args=\fIargs\fR] + [--set-default=\fIkernel-path\fR] [--set-default-index=\fIentry-index\fR] + [--title=entry-title] [--add-multiboot=\fImultiboot-path\fR] +@@ -48,7 +48,7 @@ with that title are used. + Add a new boot entry for the kernel located at \fIkernel-path\fR. + + .TP +-\fB-\-set-entry\fR=\fIentry-index\fR ++\fB-\-set-index\fR=\fIentry-index\fR + Set the position at which to add a new entry created with \fB-\-add-kernel\fR. + + .TP +-- +2.5.5 + diff --git a/SOURCES/0052-Fix-a-typo-on-the-rhel-7.3-branch.patch b/SOURCES/0052-Fix-a-typo-on-the-rhel-7.3-branch.patch new file mode 100644 index 0000000..4c7585f --- /dev/null +++ b/SOURCES/0052-Fix-a-typo-on-the-rhel-7.3-branch.patch @@ -0,0 +1,29 @@ +From 2cb2f8a419f10c5cf808572c80f51c1df09d1de0 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 23 Jun 2016 16:10:29 -0400 +Subject: [PATCH 52/55] Fix a typo on the rhel-7.3 branch... + +Apparently introduced an error resolving a conflict on this branch, +woops. + +Related: rhbz#1285601 +--- + grubby.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grubby.c b/grubby.c +index 0c260f2..2402116 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -4286,7 +4286,7 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template, + const char *newKernelPath, const char *newKernelTitle, + const char *newKernelArgs, const char *newKernelInitrd, + const char **extraInitrds, int extraInitrdCount, +- const char *newMBKernel, const char *newMBKernelArgs ++ const char *newMBKernel, const char *newMBKernelArgs, + int newIndex) + { + struct singleEntry *new, *entry, *prev = NULL; +-- +2.5.5 + diff --git a/SOURCES/0053-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch b/SOURCES/0053-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch new file mode 100644 index 0000000..1a69e77 --- /dev/null +++ b/SOURCES/0053-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch @@ -0,0 +1,386 @@ +From e6d22da1ef26780c73b610c4d64552da84b7fa34 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 24 Jun 2016 16:13:41 -0400 +Subject: [PATCH 53/55] Add a test case for a failure rmarshall saw in + --set-index= + +Related: rhbz#1285601 + +Signed-off-by: Peter Jones +--- + test.sh | 9 ++ + test/grub2-support_files/grubenv.3 | 3 + + test/grub2.18 | 154 ++++++++++++++++++++++++++++++++++ + test/results/add/g2-1.18 | 168 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 334 insertions(+) + create mode 100644 test/grub2-support_files/grubenv.3 + create mode 100644 test/grub2.18 + create mode 100644 test/results/add/g2-1.18 + +diff --git a/test.sh b/test.sh +index 9ac0ec9..dbf7507 100755 +--- a/test.sh ++++ b/test.sh +@@ -570,6 +570,15 @@ if [ "$testgrub2" == "y" ]; then + --copy-default --title 'Red Hat Enterprise Linux Server' \ + --args=root=/dev/mapper/foo-- + ++ # copy a stanza and add arguments as well, while using --set-index= ++ testing="GRUB2 add stanza and new args with --set-index=" ++ grub2Test grub2.18 add/g2-1.18 --env grubenv.3 \ ++ --add-kernel=/boot/vmlinuz-3.10.0-327.22.2.el7.x86_64.debug \ ++ --boot-filesystem=/boot --copy-default \ ++ --title "Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo) with debugging" \ ++ --args="root=/dev/mapper/rhel_team--area--222-root systemd.log_level=debug systemd.log_target=kmsg" \ ++ --set-index=1 ++ + testing="GRUB2 add initrd" + grub2Test grub2.2 add/g2-1.4 --update-kernel=/boot/new-kernel.img \ + --initrd=/boot/new-initrd --boot-filesystem=/boot/ +diff --git a/test/grub2-support_files/grubenv.3 b/test/grub2-support_files/grubenv.3 +new file mode 100644 +index 0000000..b9a8c79 +--- /dev/null ++++ b/test/grub2-support_files/grubenv.3 +@@ -0,0 +1,3 @@ ++# GRUB Environment Block ++saved_entry=Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo) with debugging ++############################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################# +\ No newline at end of file +diff --git a/test/grub2.18 b/test/grub2.18 +new file mode 100644 +index 0000000..529608d +--- /dev/null ++++ b/test/grub2.18 +@@ -0,0 +1,154 @@ ++# ++# DO NOT EDIT THIS FILE ++# ++# It is automatically generated by grub2-mkconfig using templates ++# from /etc/grub.d and settings from /etc/default/grub ++# ++ ++### BEGIN /etc/grub.d/00_header ### ++set pager=1 ++ ++if [ -s $prefix/grubenv ]; then ++ load_env ++fi ++if [ "${next_entry}" ] ; then ++ set default="${next_entry}" ++ set next_entry= ++ save_env next_entry ++ set boot_once=true ++else ++ set default="${saved_entry}" ++fi ++ ++if [ x"${feature_menuentry_id}" = xy ]; then ++ menuentry_id_option="--id" ++else ++ menuentry_id_option="" ++fi ++ ++export menuentry_id_option ++ ++if [ "${prev_saved_entry}" ]; then ++ set saved_entry="${prev_saved_entry}" ++ save_env saved_entry ++ set prev_saved_entry= ++ save_env prev_saved_entry ++ set boot_once=true ++fi ++ ++function savedefault { ++ if [ -z "${boot_once}" ]; then ++ saved_entry="${chosen}" ++ save_env saved_entry ++ fi ++} ++ ++function load_video { ++ if [ x$feature_all_video_module = xy ]; then ++ insmod all_video ++ else ++ insmod efi_gop ++ insmod efi_uga ++ insmod ieee1275_fb ++ insmod vbe ++ insmod vga ++ insmod video_bochs ++ insmod video_cirrus ++ fi ++} ++ ++terminal_output console ++if [ x$feature_timeout_style = xy ] ; then ++ set timeout_style=menu ++ set timeout=5 ++# Fallback normal timeout code in case the timeout_style feature is ++# unavailable. ++else ++ set timeout=5 ++fi ++### END /etc/grub.d/00_header ### ++ ++### BEGIN /etc/grub.d/00_tuned ### ++set tuned_params="" ++### END /etc/grub.d/00_tuned ### ++ ++### BEGIN /etc/grub.d/01_users ### ++if [ -f ${prefix}/user.cfg ]; then ++ source ${prefix}/user.cfg ++ if [ -n ${GRUB2_PASSWORD} ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root ${GRUB2_PASSWORD} ++ fi ++fi ++### END /etc/grub.d/01_users ### ++ ++### BEGIN /etc/grub.d/10_linux ### ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ else ++ search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ fi ++ linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64.debug root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ else ++ search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ fi ++ linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8 ++ initrd16 /initramfs-3.10.0-327.el7.x86_64.img ++} ++menuentry 'Red Hat Enterprise Linux Server (0-rescue-925cd320373b6a4a9a66a26371afccd2) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-925cd320373b6a4a9a66a26371afccd2-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' { ++ load_video ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ else ++ search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ fi ++ linux16 /vmlinuz-0-rescue-925cd320373b6a4a9a66a26371afccd2 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet ++ initrd16 /initramfs-0-rescue-925cd320373b6a4a9a66a26371afccd2.img ++} ++ ++### END /etc/grub.d/10_linux ### ++ ++### BEGIN /etc/grub.d/20_linux_xen ### ++### END /etc/grub.d/20_linux_xen ### ++ ++### BEGIN /etc/grub.d/20_ppc_terminfo ### ++### END /etc/grub.d/20_ppc_terminfo ### ++ ++### BEGIN /etc/grub.d/30_os-prober ### ++### END /etc/grub.d/30_os-prober ### ++ ++### BEGIN /etc/grub.d/40_custom ### ++# This file provides an easy way to add custom menu entries. Simply type the ++# menu entries you want to add after this comment. Be careful not to change ++# the 'exec tail' line above. ++### END /etc/grub.d/40_custom ### ++ ++### BEGIN /etc/grub.d/41_custom ### ++if [ -f ${config_directory}/custom.cfg ]; then ++ source ${config_directory}/custom.cfg ++elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then ++ source $prefix/custom.cfg; ++fi ++### END /etc/grub.d/41_custom ### +diff --git a/test/results/add/g2-1.18 b/test/results/add/g2-1.18 +new file mode 100644 +index 0000000..ca5fe23 +--- /dev/null ++++ b/test/results/add/g2-1.18 +@@ -0,0 +1,168 @@ ++# ++# DO NOT EDIT THIS FILE ++# ++# It is automatically generated by grub2-mkconfig using templates ++# from /etc/grub.d and settings from /etc/default/grub ++# ++ ++### BEGIN /etc/grub.d/00_header ### ++set pager=1 ++ ++if [ -s $prefix/grubenv ]; then ++ load_env ++fi ++if [ "${next_entry}" ] ; then ++ set default="${next_entry}" ++ set next_entry= ++ save_env next_entry ++ set boot_once=true ++else ++ set default="${saved_entry}" ++fi ++ ++if [ x"${feature_menuentry_id}" = xy ]; then ++ menuentry_id_option="--id" ++else ++ menuentry_id_option="" ++fi ++ ++export menuentry_id_option ++ ++if [ "${prev_saved_entry}" ]; then ++ set saved_entry="${prev_saved_entry}" ++ save_env saved_entry ++ set prev_saved_entry= ++ save_env prev_saved_entry ++ set boot_once=true ++fi ++ ++function savedefault { ++ if [ -z "${boot_once}" ]; then ++ saved_entry="${chosen}" ++ save_env saved_entry ++ fi ++} ++ ++function load_video { ++ if [ x$feature_all_video_module = xy ]; then ++ insmod all_video ++ else ++ insmod efi_gop ++ insmod efi_uga ++ insmod ieee1275_fb ++ insmod vbe ++ insmod vga ++ insmod video_bochs ++ insmod video_cirrus ++ fi ++} ++ ++terminal_output console ++if [ x$feature_timeout_style = xy ] ; then ++ set timeout_style=menu ++ set timeout=5 ++# Fallback normal timeout code in case the timeout_style feature is ++# unavailable. ++else ++ set timeout=5 ++fi ++### END /etc/grub.d/00_header ### ++ ++### BEGIN /etc/grub.d/00_tuned ### ++set tuned_params="" ++### END /etc/grub.d/00_tuned ### ++ ++### BEGIN /etc/grub.d/01_users ### ++if [ -f ${prefix}/user.cfg ]; then ++ source ${prefix}/user.cfg ++ if [ -n ${GRUB2_PASSWORD} ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root ${GRUB2_PASSWORD} ++ fi ++fi ++### END /etc/grub.d/01_users ### ++ ++### BEGIN /etc/grub.d/10_linux ### ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ else ++ search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ fi ++ linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64.debug root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8 ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo) with debugging' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ else ++ search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ fi ++ linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64.debug root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8 systemd.log_level=debug systemd.log_target=kmsg ++} ++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' { ++ load_video ++ set gfxpayload=keep ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ else ++ search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ fi ++ linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8 ++ initrd16 /initramfs-3.10.0-327.el7.x86_64.img ++} ++menuentry 'Red Hat Enterprise Linux Server (0-rescue-925cd320373b6a4a9a66a26371afccd2) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-925cd320373b6a4a9a66a26371afccd2-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' { ++ load_video ++ insmod gzio ++ insmod part_msdos ++ insmod xfs ++ set root='hd0,msdos1' ++ if [ x$feature_platform_search_hint = xy ]; then ++ search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ else ++ search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d ++ fi ++ linux16 /vmlinuz-0-rescue-925cd320373b6a4a9a66a26371afccd2 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet ++ initrd16 /initramfs-0-rescue-925cd320373b6a4a9a66a26371afccd2.img ++} ++ ++### END /etc/grub.d/10_linux ### ++ ++### BEGIN /etc/grub.d/20_linux_xen ### ++### END /etc/grub.d/20_linux_xen ### ++ ++### BEGIN /etc/grub.d/20_ppc_terminfo ### ++### END /etc/grub.d/20_ppc_terminfo ### ++ ++### BEGIN /etc/grub.d/30_os-prober ### ++### END /etc/grub.d/30_os-prober ### ++ ++### BEGIN /etc/grub.d/40_custom ### ++# This file provides an easy way to add custom menu entries. Simply type the ++# menu entries you want to add after this comment. Be careful not to change ++# the 'exec tail' line above. ++### END /etc/grub.d/40_custom ### ++ ++### BEGIN /etc/grub.d/41_custom ### ++if [ -f ${config_directory}/custom.cfg ]; then ++ source ${config_directory}/custom.cfg ++elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then ++ source $prefix/custom.cfg; ++fi ++### END /etc/grub.d/41_custom ### +-- +2.5.5 + diff --git a/SOURCES/0054-Ensure-command-line-updates-also-honor-set-index.patch b/SOURCES/0054-Ensure-command-line-updates-also-honor-set-index.patch new file mode 100644 index 0000000..022d0c9 --- /dev/null +++ b/SOURCES/0054-Ensure-command-line-updates-also-honor-set-index.patch @@ -0,0 +1,46 @@ +From d4d7954a983f9cf68cd49c181e8deb1493e76e9e Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 24 Jun 2016 16:05:45 -0400 +Subject: [PATCH 54/55] Ensure command line updates also honor --set-index + +Related: rhbz#1285601 + +Signed-off-by: Peter Jones +--- + grubby.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/grubby.c b/grubby.c +index 2402116..c379388 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -4292,11 +4292,17 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template, + struct singleEntry *new, *entry, *prev = NULL; + struct singleLine *newLine = NULL, *tmplLine = NULL, *masterLine = NULL; + int needs; ++ char *indexs; + char *chptr; ++ int rc; + + if (!newKernelPath) + return 0; + ++ rc = asprintf(&indexs, "%d", newIndex); ++ if (rc < 0) ++ return 1; ++ + /* if the newKernelTitle is too long silently munge it into something + * we can live with. truncating is first check, then we'll just mess with + * it until it looks better */ +@@ -4753,7 +4759,7 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template, + abort(); + } + +- if (updateImage(config, "0", prefix, newKernelArgs, NULL, ++ if (updateImage(config, indexs, prefix, newKernelArgs, NULL, + newMBKernelArgs, NULL)) + return 1; + +-- +2.5.5 + diff --git a/SOURCES/0055-Change-debug-entry-insertion-order-rhbz-1285601.patch b/SOURCES/0055-Change-debug-entry-insertion-order-rhbz-1285601.patch new file mode 100644 index 0000000..71ddd3c --- /dev/null +++ b/SOURCES/0055-Change-debug-entry-insertion-order-rhbz-1285601.patch @@ -0,0 +1,67 @@ +From 089057d3c574ec804c967dcd4ae8a0368e7ee90f Mon Sep 17 00:00:00 2001 +From: Robert Marshall +Date: Thu, 23 Jun 2016 14:41:12 -0400 +Subject: [PATCH 55/55] Change debug entry insertion order (rhbz#1285601) + +Customer reports indicated that it was confusing to have the debugging +entries before non-debugging entries. Altered the insertion code to use +the --set-index feature on the debug kernels to force them to insert +after the initial non-debugging entry. + +Resolves: rhbz#1285601 +--- + new-kernel-pkg | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/new-kernel-pkg b/new-kernel-pkg +index bd28634..847e959 100755 +--- a/new-kernel-pkg ++++ b/new-kernel-pkg +@@ -238,7 +238,7 @@ install() { + --remove-kernel=\"TITLE=$title\$debugtitle\"" + + rungrubby ${ARGS} $makedefault +- rungrubby --debug ${ARGS} ++ rungrubby --debug ${ARGS} --set-index=1 + else + [ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby for grub 0.97" + fi +@@ -252,7 +252,7 @@ install() { + --args=\"root=$rootdevice $kernargs \$debugargs\" \ + --remove-kernel=\"TITLE=$title\$debugtitle\"" + rungrubby ${ARGS} $makedefault +- rungrubby --debug ${ARGS} ++ rungrubby --debug ${ARGS} --set-index=1 + else + [ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby for grub 2" + fi +@@ -267,7 +267,7 @@ install() { + --args=\"root=$rootdevice $kernargs \$debugargs\" \ + --remove-kernel=\"TITLE=$title\$debugtitle\"" + rungrubby ${ARGS} $makedefault +- rungrubby --debug ${ARGS} ++ rungrubby --debug ${ARGS} --set-index=1 + else + [ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby for grub 2 with UEFI" + fi +@@ -283,7 +283,7 @@ install() { + --remove-kernel=\"TITLE=$version\"" + + rungrubby ${ARGS} $makedefault +- rungrubby --debug ${ARGS} ++ rungrubby --debug ${ARGS} --set-index=1 + if [ -n "$runLilo" ]; then + [ -n "$verbose" ] && echo "running $lilo" + if [ ! -x $lilo ] ; then +@@ -307,7 +307,7 @@ install() { + --remove-kernel=\"TITLE=$title\$debugtitle\"" + + rungrubby ${ARGS} $makedefault +- rungrubby --debug ${ARGS} ++ rungrubby --debug ${ARGS} --set-index=1 + else + [ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby for extlinux" + fi +-- +2.5.5 + diff --git a/SOURCES/0056-Reorganize-grubby-man-page-1232168.patch b/SOURCES/0056-Reorganize-grubby-man-page-1232168.patch new file mode 100644 index 0000000..ac0e298 --- /dev/null +++ b/SOURCES/0056-Reorganize-grubby-man-page-1232168.patch @@ -0,0 +1,339 @@ +From 31537e66c2830783c4037ebace6801356b7ba520 Mon Sep 17 00:00:00 2001 +From: Robert Marshall +Date: Fri, 1 Jul 2016 14:54:30 -0400 +Subject: [PATCH 56/60] Reorganize grubby man page (#1232168) + +Broke the grubby man page into clearer sections and re-organized the +content by general use case for easier reading. + +Related: rhbz#1232168 +--- + grubby.8 | 197 +++++++++++++++++++++++++++++++++++---------------------------- + 1 file changed, 109 insertions(+), 88 deletions(-) + +diff --git a/grubby.8 b/grubby.8 +index 709a539..005a6c2 100644 +--- a/grubby.8 ++++ b/grubby.8 +@@ -1,10 +1,13 @@ + .TH GRUBBY 8 "Tue Jan 18 2005" ++ + .SH NAME ++ + grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl + + .SH SYNOPSIS +-\fBgrubby\fR [--add-kernel=\fIkernel-path\fR] [--args=\fIargs\fR] +- [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR] ++ ++\fBgrubby\fR [--add-kernel=\fIkernel-path\fR] [--args=\fIargs\fR] ++ [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR] + [--bootloader-probe] [--config-file \fIpath\fR] [--copy-default] + [--debug] [--default-kernel] [--default-index] [--default-title] + [--grub] [--lilo] [--yaboot] [--silo] [--zipl] +@@ -17,12 +20,17 @@ grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl + [--remove-mbargs=\fIargs\fR] + + .SH DESCRIPTION ++ ++.SS General Information ++ + \fBgrubby\fR is a command line tool for updating and displaying information + about the configuration files for the \fBgrub\fR, \fBlilo\fR, \fBelilo\fR + (ia64), \fByaboot\fR (powerpc) and \fBzipl\fR (s390) boot loaders. It + is primarily designed to be used from scripts which install new + kernels and need to find information about the current boot environment. + ++.SS Architecture Support ++ + On BIOS-based Intel x86 platforms, \fBgrub2\fR is the default bootloader and + the configuration file is in \fB/boot/grub2/grub.cfg\fR. On UEFI-based Intel + x86 platforms, \fBgrub2\fR is the default bootloader, and the configuration +@@ -34,6 +42,8 @@ config stored in \fB/boot/grub2/grub.cfg\fR. The earlier Power7 systems use \fBy + parsing and the configuration file should be in \fB/etc/yaboot.conf\fR. On + s390 platforms the \fBzipl bootloader\fR will read from \fB/etc/zipl.conf\fR. + ++.SS Special Arguments ++ + There are a number of ways to specify the kernel used for \fB-\-info\fR, + \fB-\-remove-kernel\fR, and \fB-\-update-kernel\fR. Specificying \fBDEFAULT\fR + or \fBALL\fR selects the default entry and all of the entries, respectively. +@@ -43,13 +53,24 @@ be specified by using \fBTITLE=\fItitle\fR as the argument; all entries + with that title are used. + + .SH OPTIONS ++ ++.SS Basic Options ++ + .TP + \fB-\-add-kernel\fR=\fIkernel-path\fR + Add a new boot entry for the kernel located at \fIkernel-path\fR. + + .TP +-\fB-\-set-index\fR=\fIentry-index\fR +-Set the position at which to add a new entry created with \fB-\-add-kernel\fR. ++\fB-\-remove-kernel\fR=\fIkernel-path\fR ++Removes all boot entries which match \fIkernel-path\fR. This may be used ++along with -\-add-kernel, in which case the new kernel being added will ++never be removed. ++ ++.TP ++\fB-\-update-kernel\fR=\fIkernel-path\fR ++The entries for kernels matching \fRkernel-path\fR are updated. Currently ++the only items that can be updated is the kernel argument list, which is ++modified via the \fB-\-args\fR and \fB-\-remove-args\fR options. + + .TP + \fB-\-args\fR=\fIkernel-args\fR +@@ -64,49 +85,53 @@ file has special handling for specifying the root filesystem (like + lilo.conf does). + + .TP +-\fB-\-bad-image-okay\fR +-When \fBgrubby\fR is looking for a entry to use for something (such +-as a template or a default boot entry) it uses sanity checks, such as +-ensuring that the kernel exists in the filesystem, to make sure +-entries that obviously won't work aren't selected. This option overrides +-that behavior, and is designed primarily for testing. ++\fB-\-remove-args\fR=\fIkernel-args\fR ++The arguments specified by \fIkernel-args\fR are removed from the ++kernels specified by \fB-\-update-kernel\fR. The \fBroot\fR argument ++gets special handling for configuration files that support separate root ++filesystem configuration. + + .TP +-\fB-\-boot-filesystem\fR=\fIbootfs\fR +-The \fBgrub\fR boot loader expects file paths listed in it's configuration +-path to be relative to the top of the filesystem they are on, rather then +-relative to the current root filesystem. By default \fBgrubby\fR searches +-the list of currently mounted filesystems to determine this. If this option +-is given \fBgrubby\fR acts as if the specified filesystem was the filesystem +-containing the kernel (this option is designed primarily for testing). ++\fB-\-copy-default\fR ++\fBgrubby\fR will copy as much information (such as kernel arguments and ++root device) as possible from the current default kernel. The kernel path ++and initrd path will never be copied. + + .TP +-\fB-\-bootloader-probe\fR +-\fBgrubby\fR tries to determine if \fBgrub\fR or \fBlilo\fR is currently +-installed. When one of those bootloaders is found the name of that bootloader +-is displayed on stdout. Both could be installed (on different devices), and +-grubby will print out the names of both bootloaders, one per line. The probe +-for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR +-identical to the standard directive in the lilo configuration file. If this +-is not present \fBgrubby\fR will assume grub is not installed (note +-that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates). +-This option is only available on ia32 platforms. ++\fB-\-title\fR=\fIentry-title\fR ++When a new kernel entry is added \fIentry-title\fR is used as the title ++(\fBlilo\fR label) for the entry. If \fIentry-title\fR is longer then maximum ++length allowed by the bootloader (15 for lilo, unlimited for grub and elilo) ++the title is shortened to a (unique) entry. + ++.TP ++\fB-\-initrd\fR=\fIinitrd-path\fR ++Use \fIinitrd-path\fR as the path to an initial ram disk for a new kernel ++being added. + + .TP +-\fB-\-config-file\fR=\fIpath\fR +-Use \fIpath\fR as the configuration file rather then the default. ++\fB-\-set-default\fR=\fIkernel-path\fR ++The first entry which boots the specified kernel is made the default ++boot entry. + + .TP +-\fB-\-copy-default\fR +-\fBgrubby\fR will copy as much information (such as kernel arguments and +-root device) as possible from the current default kernel. The kernel path +-and initrd path will never be copied. ++\fB-\-set-default-index\fR=\fIentry-index\fR ++Makes the given entry number the default boot entry. ++ ++.TP ++\fB-\-make-default\fR ++Make the new kernel entry being added the default entry. ++ ++.TP ++\fB-\-set-index\fR=\fIentry-index\fR ++Set the position at which to add a new entry created with \fB-\-add-kernel\fR. + + .TP + \fB-\-debug\fR + Display extra debugging information for failures. + ++.SS Display Options ++ + .TP + \fB-\-default-kernel\fR + Display the full path to the current default kernel and exit. +@@ -120,79 +145,73 @@ Display the numeric index of the current default boot entry and exit. + Display the title of the current default boot entry and exit. + + .TP +-\fB-\-elilo\fR +-Use an \fBelilo\fR style configuration file. +- +-.TP +-\fB-\-grub\fR +-Use a \fBgrub\fR style configuration file instead of \fBlilo\fR style. This +-is the default on ia32 platforms. +- +-.TP + \fB-\-info\fR=\fIkernel-path\fR + Display information on all boot entries which match \fIkernel-path\fR. I + + .TP +-\fB-\-initrd\fR=\fIinitrd-path\fR +-Use \fIinitrd-path\fR as the path to an initial ram disk for a new kernel +-being added. ++\fB-\-bootloader-probe\fR ++\fBgrubby\fR tries to determine if \fBgrub\fR or \fBlilo\fR is currently ++installed. When one of those bootloaders is found the name of that bootloader ++is displayed on stdout. Both could be installed (on different devices), and ++grubby will print out the names of both bootloaders, one per line. The probe ++for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR ++identical to the standard directive in the lilo configuration file. If this ++is not present \fBgrubby\fR will assume grub is not installed (note ++that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates). ++This option is only available on ia32 platforms. + + .TP +-\fB-\-lilo\fR +-Use a \fBlilo\fR style configuration file. ++\fB-\-version\fR ++Display the version of \fBgrubby\fR being run and then exit immediately. + +-.TP +-\fB-\-make-default\fR +-Make the new kernel entry being added the default entry. ++.SS Output Format Options + + .TP +-\fB-\-remove-args\fR=\fIkernel-args\fR +-The arguments specified by \fIkernel-args\fR are removed from the +-kernels specified by \fB-\-update-kernel\fR. The \fBroot\fR argument +-gets special handling for configuration files that support separate root +-filesystem configuration. ++\fB-\-elilo\fR ++Use an \fBelilo\fR style configuration file. + + .TP +-\fB-\-remove-kernel\fR=\fIkernel-path\fR +-Removes all boot entries which match \fIkernel-path\fR. This may be used +-along with -\-add-kernel, in which case the new kernel being added will +-never be removed. ++\fB-\-grub\fR ++Use a \fBgrub\fR style configuration file instead of \fBlilo\fR style. This ++is the default on ia32 platforms. + + .TP +-\fB-\-set-default\fR=\fIkernel-path\fR +-The first entry which boots the specified kernel is made the default +-boot entry. ++\fB-\-lilo\fR ++Use a \fBlilo\fR style configuration file. + + .TP +-\fB-\-set-default-index\fR=\fIentry-index\fR +-Makes the given entry number the default boot entry. ++\fB-\-yaboot\fR ++Use an \fByaboot\fR style configuration file. + + .TP +-\fB-\-title\fR=\fIentry-title\fR +-When a new kernel entry is added \fIentry-title\fR is used as the title +-(\fBlilo\fR label) for the entry. If \fIentry-title\fR is longer then maximum +-length allowed by the bootloader (15 for lilo, unlimited for grub and elilo) +-the title is shortened to a (unique) entry. ++\fB-\-zipl\fR ++Use an \fBzipl\fR style configuration file. + +-.TP +-\fB-\-update-kernel\fR=\fIkernel-path\fR +-The entries for kernels matching \fRkernel-path\fR are updated. Currently +-the only items that can be updated is the kernel argument list, which is +-modified via the \fB-\-args\fR and \fB-\-remove-args\fR options. ++.SS Override Options + + .TP +-\fB-\-version\fR +-Display the version of \fBgrubby\fR being run and then exit immediately. ++\fB-\-bad-image-okay\fR ++When \fBgrubby\fR is looking for a entry to use for something (such ++as a template or a default boot entry) it uses sanity checks, such as ++ensuring that the kernel exists in the filesystem, to make sure ++entries that obviously won't work aren't selected. This option overrides ++that behavior, and is designed primarily for testing. + + .TP +-\fB-\-yaboot\fR +-Use an \fByaboot\fR style configuration file. ++\fB-\-boot-filesystem\fR=\fIbootfs\fR ++The \fBgrub\fR boot loader expects file paths listed in it's configuration ++path to be relative to the top of the filesystem they are on, rather then ++relative to the current root filesystem. By default \fBgrubby\fR searches ++the list of currently mounted filesystems to determine this. If this option ++is given \fBgrubby\fR acts as if the specified filesystem was the filesystem ++containing the kernel (this option is designed primarily for testing). + + .TP +-\fB-\-zipl\fR +-Use an \fBzipl\fR style configuration file. ++\fB-\-config-file\fR=\fIpath\fR ++Use \fIpath\fR as the configuration file rather then the default. ++ ++.SS Multiboot Options + +-.SH MULTIBOOT OPTIONS + The Multiboot Specification provides a genreic interface for boot + loaders and operating systems. It is supported by the GRUB bootloader. + +@@ -204,34 +223,36 @@ Add a new boot entry for the multiboot kernel located at + + .TP + \fB-\-remove-multiboot\fR=\fImultiboot-path\fR +-Removes all boot entries which match \fImultiboot-path\fR. ++Removes all boot entries which match \fImultiboot-path\fR. + + .TP + \fB-\-mbargs\fR=\fImultiboot-args\fR +-When a new multiboot kernel is added, this specifies the command line +-arguments which should be passed to that kernel by default ++When a new multiboot kernel is added, this specifies the command line ++arguments which should be passed to that kernel by default + When \fB-\-update-kernel\fR is used, this specifies new arguments to add + to the argument list. Multiple, space separated arguments may be used. If +-an argument already exists the new value replaces the old values. ++an argument already exists the new value replaces the old values. + + .TP + \fB-\-remove-mbargs\fR=\fImultiboot-args\fR +-The arguments specified by \fImultiboot-args\fR are removed from the +-kernels specified by \fB-\-update-kernel\fR. +- ++The arguments specified by \fImultiboot-args\fR are removed from the ++kernels specified by \fB-\-update-kernel\fR. + + .SH "BUGS" ++ + The command line syntax is more than a little baroque. This probably + won't be fixed as \fBgrubby\fR is only intended to be called from shell + scripts which can get it right. + + .SH "SEE ALSO" ++ + .BR grub (8), + .BR lilo (8), + .BR yaboot (8), + .BR mkinitrd (8) + + .SH AUTHORS ++ + .nf + Erik Troan + Jeremy Katz +-- +2.5.5 + diff --git a/SOURCES/0057-Update-grubby-man-page-contents-bz1232168.patch b/SOURCES/0057-Update-grubby-man-page-contents-bz1232168.patch new file mode 100644 index 0000000..9d2d710 --- /dev/null +++ b/SOURCES/0057-Update-grubby-man-page-contents-bz1232168.patch @@ -0,0 +1,355 @@ +From ffc9203275b76bbc4d721b54157f68bfec5e1a2d Mon Sep 17 00:00:00 2001 +From: Robert Marshall +Date: Fri, 1 Jul 2016 15:18:07 -0400 +Subject: [PATCH 57/60] Update grubby man page contents (#bz1232168) + +The grubby man page was missing several options that were added in +previous releases. Added those to the man page as well as updated the +text on others to provide further clarity. + +Added an EXAMPLE section containing some basic use cases. + +Resolves: rhbz#1232168 +--- + grubby.8 | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 165 insertions(+), 43 deletions(-) + +diff --git a/grubby.8 b/grubby.8 +index 005a6c2..5e1b521 100644 +--- a/grubby.8 ++++ b/grubby.8 +@@ -2,50 +2,69 @@ + + .SH NAME + +-grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl ++grubby \- command line tool used to configure bootloader menu entries across multiple architectures + + .SH SYNOPSIS + +-\fBgrubby\fR [--add-kernel=\fIkernel-path\fR] [--args=\fIargs\fR] +- [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR] +- [--bootloader-probe] [--config-file \fIpath\fR] [--copy-default] +- [--debug] [--default-kernel] [--default-index] [--default-title] +- [--grub] [--lilo] [--yaboot] [--silo] [--zipl] +- [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR] +- [--make-default] [-o path] [--version] [--set-index=\fIentry-index\fR] +- [--remove-kernel=\fIkernel-path\fR] [--remove-args=\fIargs\fR] +- [--set-default=\fIkernel-path\fR] [--set-default-index=\fIentry-index\fR] +- [--title=entry-title] [--add-multiboot=\fImultiboot-path\fR] +- [--mbargs=\fIargs\fR] [--remove-multiboot=\fImultiboot-path\fR] +- [--remove-mbargs=\fIargs\fR] ++\fBgrubby\fR [\fIOPTIONS...\fR] + + .SH DESCRIPTION + + .SS General Information + + \fBgrubby\fR is a command line tool for updating and displaying information +-about the configuration files for the \fBgrub\fR, \fBlilo\fR, \fBelilo\fR +-(ia64), \fByaboot\fR (powerpc) and \fBzipl\fR (s390) boot loaders. It +-is primarily designed to be used from scripts which install new +-kernels and need to find information about the current boot environment. ++about the configuration files for various architecture specific bootloaders. ++It is primarily designed to be used from scripts which install new kernels ++and need to find information about the current boot environment. + + .SS Architecture Support + +-On BIOS-based Intel x86 platforms, \fBgrub2\fR is the default bootloader and +-the configuration file is in \fB/boot/grub2/grub.cfg\fR. On UEFI-based Intel +-x86 platforms, \fBgrub2\fR is the default bootloader, and the configuration +-file is in \fB/boot/efi/EFI/redhat/grub.cfg\fR. On Intel ia64 platforms, +-\fBelilo\fR mode is used and the default location for the configuration file +-is \fB/boot/efi/EFI/redhat/elilo.conf\fR. On PowerPC platforms, systems based +-on Power8 now support \fBgrub2\fR as a bootloader and store using a default +-config stored in \fB/boot/grub2/grub.cfg\fR. The earlier Power7 systems use \fByaboot\fR +-parsing and the configuration file should be in \fB/etc/yaboot.conf\fR. On +-s390 platforms the \fBzipl bootloader\fR will read from \fB/etc/zipl.conf\fR. ++The \fBgrubby\fR executable has full support for the \fBgrub2\fR ++bootloader on \fBx86_64\fR systems using legacy BIOS or modern ++UEFI firmware and \fBppc64\fR and \fBppc64le\fR hardware using ++OPAL or SLOF as firmware. ++ ++Legacy \fBs390\fR and the current \fBs390x\fR architectures ++and their \fBzipl\fR bootloader are fully supported. ++ ++Support for \fByaboot\fR has been deprecated as all ppc architecture ++hardware since the Power8 system uses \fBgrub2\fR or petitboot ++which both use the grub2 configuration file format. ++ ++Legacy bootloaders \fBLILO\fR, \fBSILO\fR, and \fBELILO\fR ++are deprecated in favor of previously mentioned bootloaders. The ++\fBSILO\fR bootloader should also be considered unsupported. ++ ++.SS Default Behavior ++ ++The default architecture is chosen at compile time. The grubby executable ++has a series of built in assumptions about what bootloader is being used and ++where its configuration file lives. If no output format option is specified ++on the command line then grubby will use these default settings to first ++search for an existing configuration and, if it is not found, assume that ++it should be placed in the standard location. These default assumptions are ++listed in the table below. ++ ++.TS ++allbox; ++lbw6 lbw10 lbw18 ++l l l. ++ Arch Bootloader Configuration File ++ x86_64 [BIOS] grub2 /boot/grub2/grub.cfg ++ x86_64 [UEFI] grub2 /boot/efi/EFI/redhat/grub.cfg ++ i386 grub2 /boot/grub2/grub.cfg ++ ia64 elilo /boot/efi/EFI/redhat/elilo.conf ++ ppc [>=Power8] grub2 /boot/grub2/grub.cfg ++ ppc [<=Power7] yaboot /etc/yaboot.conf ++ s390 zipl /etc/zipl.conf ++ s390x zipl /etc/zipl.conf ++.TE ++ + + .SS Special Arguments + + There are a number of ways to specify the kernel used for \fB-\-info\fR, +-\fB-\-remove-kernel\fR, and \fB-\-update-kernel\fR. Specificying \fBDEFAULT\fR ++\fB-\-remove-kernel\fR, and \fB-\-update-kernel\fR. Specifying \fBDEFAULT\fR + or \fBALL\fR selects the default entry and all of the entries, respectively. + If a comma separated list of numbers is given, the boot entries indexed + by those numbers are selected. Finally, the title of a boot entry may +@@ -58,12 +77,17 @@ with that title are used. + + .TP + \fB-\-add-kernel\fR=\fIkernel-path\fR +-Add a new boot entry for the kernel located at \fIkernel-path\fR. ++Add a new boot entry for the kernel located at \fIkernel-path\fR. A title for ++the boot entry must be set using \fB-\-title\fR. Most invocations should also ++include \fB-\-initrd\fR with memtest86 as a notable exception. ++ ++The \fB-\-update-kernel\fR ++option may not be used in the same invocation. + + .TP + \fB-\-remove-kernel\fR=\fIkernel-path\fR + Removes all boot entries which match \fIkernel-path\fR. This may be used +-along with -\-add-kernel, in which case the new kernel being added will ++along with \fB-\-add-kernel\fR, in which case the new kernel being added will + never be removed. + + .TP +@@ -110,13 +134,18 @@ Use \fIinitrd-path\fR as the path to an initial ram disk for a new kernel + being added. + + .TP ++\fB-\-efi\fR ++Use linuxefi and initrdefi when constructing bootloader stanzas instead of linux and initrd. ++ ++.TP + \fB-\-set-default\fR=\fIkernel-path\fR + The first entry which boots the specified kernel is made the default +-boot entry. ++boot entry. This may not be invoked with \fB-\-set-default-index\fR. + + .TP + \fB-\-set-default-index\fR=\fIentry-index\fR +-Makes the given entry number the default boot entry. ++Makes the given entry number the default boot entry. This may not ++be invoked with \fB-\-set-default\fR. + + .TP + \fB-\-make-default\fR +@@ -130,8 +159,17 @@ Set the position at which to add a new entry created with \fB-\-add-kernel\fR. + \fB-\-debug\fR + Display extra debugging information for failures. + ++.TP ++\fB-i\fR, \fB-\-extra-initrd\fR=\fIinitrd-path\fR ++Use \fIinitrd-path\fR as the path for an auxiliary initrd image. ++ + .SS Display Options + ++Passing the display option to grubby will cause it to print out the ++requested information about the current bootloader configuration and ++then immediately exit. These options should not be used in any ++script intended to update the bootloader configuration. ++ + .TP + \fB-\-default-kernel\fR + Display the full path to the current default kernel and exit. +@@ -158,34 +196,56 @@ for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR + identical to the standard directive in the lilo configuration file. If this + is not present \fBgrubby\fR will assume grub is not installed (note + that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates). +-This option is only available on ia32 platforms. ++ ++\fIThis option is only available on i386 platforms.\fR + + .TP +-\fB-\-version\fR ++\fB-v\fR, \fB-\-version\fR + Display the version of \fBgrubby\fR being run and then exit immediately. + + .SS Output Format Options + ++Sane default options for the current platform are compiled into grubby on ++a per platform basis. These defaults determine the format and layout of ++the generated bootloader configuration file. A different configuration file ++format may be specified on the command line if the system uses a supported ++alternative bootloader. ++ + .TP + \fB-\-elilo\fR +-Use an \fBelilo\fR style configuration file. ++Use an \fBelilo\fR style configuration file. This is the default on ia64 platforms. This format is deprecated. ++ ++.TP ++\fB-\-extlinux\fR ++Use an \fBextlinux\fR style configuration file. This format is deprecated. + + .TP + \fB-\-grub\fR +-Use a \fBgrub\fR style configuration file instead of \fBlilo\fR style. This +-is the default on ia32 platforms. ++Use a \fBgrub\fR style configuration file. This is the default on ia32 platforms. ++ ++.TP ++\fB-\-grub2\fR ++Use a \fBgrub2\fR style configuration file. This is the default on \fBx86_64\fR ++architecture as well as the \fBppc64\fR and \fBppc64le\fR architectures ++running on Power8 or later hardware. + + .TP + \fB-\-lilo\fR + Use a \fBlilo\fR style configuration file. + + .TP ++\fB-\-silo\fR ++Use a \fBsilo\fR style configuration file. This is the default on SPARC systems. This format is legacy, deprecated, and unsupported. ++ ++.TP + \fB-\-yaboot\fR +-Use an \fByaboot\fR style configuration file. ++Use a \fByaboot\fR style configuration file. This is the default for ++the \fBppc\fR architecture on on Power7 and earlier hardware. + + .TP + \fB-\-zipl\fR +-Use an \fBzipl\fR style configuration file. ++Use a \fBzipl\fR style configuration file. This is the default on the ++legacy s390 and current s390x architectures. + + .SS Override Options + +@@ -199,7 +259,7 @@ that behavior, and is designed primarily for testing. + + .TP + \fB-\-boot-filesystem\fR=\fIbootfs\fR +-The \fBgrub\fR boot loader expects file paths listed in it's configuration ++The \fBgrub\fR boot loader expects file paths listed in its configuration + path to be relative to the top of the filesystem they are on, rather then + relative to the current root filesystem. By default \fBgrubby\fR searches + the list of currently mounted filesystems to determine this. If this option +@@ -207,19 +267,28 @@ is given \fBgrubby\fR acts as if the specified filesystem was the filesystem + containing the kernel (this option is designed primarily for testing). + + .TP +-\fB-\-config-file\fR=\fIpath\fR ++\fB-\-env\fR=\fIpath\fR ++Path for the file where grub environment data is stored. ++ ++.TP ++\fB-c\fR, \fB-\-config-file\fR=\fIpath\fR + Use \fIpath\fR as the configuration file rather then the default. + ++.TP ++\fB-o\fR, \fB-\-output-file\fR=\fIfile_path\fR ++The destination path for the updated configuration file. Use "-" to ++send it to stdout. ++ + .SS Multiboot Options + +-The Multiboot Specification provides a genreic interface for boot ++The Multiboot Specification provides a generic interface for boot + loaders and operating systems. It is supported by the GRUB bootloader. + + .TP + \fB-\-add-multiboot\fR=\fImultiboot-path\fR + Add a new boot entry for the multiboot kernel located at + \fImultiboot-path\fR. Note that this is generally accompanied with a +-\fI--add-kernel\fR option. ++\fB--add-kernel\fR option. + + .TP + \fB-\-remove-multiboot\fR=\fImultiboot-path\fR +@@ -244,11 +313,63 @@ The command line syntax is more than a little baroque. This probably + won't be fixed as \fBgrubby\fR is only intended to be called from shell + scripts which can get it right. + ++.SH EXAMPLE ++ ++The following examples assume the following: ++ ++.TS ++allbox; ++rbw15 l. ++cfg_file Full path to bootloader config file ++new_kernel Full path to kernel image to be installed ++old_kernel Full path to old kernel image to be removed ++current_kernel Full path to a currently installed kernel ++entry_title Title that appears on bootloader menu ++new_initrd Full path to initrd for a new kernel ++kernel_args Set of arguments for the kernel ++menu_index Index number of a menu entry ++.TE ++ ++The examples below quote strings that may have spaces or other whitespace in them. It is also ++perfectly valid to backslash escape these strings if that is more convenient. ++ ++.PP ++Add a new kernel entry and copy all options from the current default kernel. This is the behavior ++that most users will want. ++.IP ++\fBgrubby\fR --add-kernel=\fInew_kernel\fR --title="\fIentry_title\fR" --initrd="\fInew_initrd\fR" --copy-default ++.PP ++Add a new kernel entry with custom arguments ++.IP ++\fBgrubby\fR --add-kernel=\fInew_kernel\fR --title="\fIentry_title\fR" --initrd="\fInew_initrd\fR" --args=\fIkernel_args\fR ++.PP ++Remove \fBall menu entries\fR for a specified kernel. ++.IP ++\fBgrubby\fR --remove-kernel=\fIold_kernel\fR ++.PP ++Target a single menu entry to remove without targetting other entries with the same kernel. ++.IP ++\fBgrubby\fR --info=\fIold_kernel\fR ++ ++\fBgrubby\fR --remove-kernel=\fImenu_index\fR ++.PP ++Update the arguments for all entries of a specific kernel. New arguments get added while existing arguments get updated values. ++.IP ++\fBgrubby\fR --update-kernel=\fIcurrent_kernel\fR --args="\fIkernel_args\fR" ++.PP ++Remove the arguments for a single entry of a specific kernel. ++.IP ++\fBgrubby\fR --info=\fIcurrent_kernel\fR ++ ++\fBgrubby\fR --remove-args=\fImenu_index\fR --args="\fIkernel_args\fR" ++ + .SH "SEE ALSO" + + .BR grub (8), + .BR lilo (8), + .BR yaboot (8), ++.BR zipl (8), ++.BR dracut (8), + .BR mkinitrd (8) + + .SH AUTHORS +@@ -257,4 +378,5 @@ scripts which can get it right. + Erik Troan + Jeremy Katz + Peter Jones ++Robert Marshall + .fi +-- +2.5.5 + diff --git a/SOURCES/0058-Fix-inline-help-typo-1232168.patch b/SOURCES/0058-Fix-inline-help-typo-1232168.patch new file mode 100644 index 0000000..a444ca2 --- /dev/null +++ b/SOURCES/0058-Fix-inline-help-typo-1232168.patch @@ -0,0 +1,29 @@ +From e016fa8fdcd15b9db94b847de6b09b369e5805b6 Mon Sep 17 00:00:00 2001 +From: Robert Marshall +Date: Fri, 1 Jul 2016 15:19:24 -0400 +Subject: [PATCH 58/60] Fix inline help typo (#1232168) + +Discovered a typo while synchronizing the inline help with the man pages +and fixed it. + +Related: rhbz#1232168 +--- + grubby.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grubby.c b/grubby.c +index c379388..ab2c025 100644 +--- a/grubby.c ++++ b/grubby.c +@@ -4824,7 +4824,7 @@ int main(int argc, const char **argv) + NULL}, + {"boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0, + _ +- ("filestystem which contains /boot directory (for testing only)"), ++ ("filesystem which contains /boot directory (for testing only)"), + _("bootfs")}, + #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__) + {"bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0, +-- +2.5.5 + diff --git a/SOURCES/0059-More-edits-for-grubby.8-1232168.patch b/SOURCES/0059-More-edits-for-grubby.8-1232168.patch new file mode 100644 index 0000000..51f6e30 --- /dev/null +++ b/SOURCES/0059-More-edits-for-grubby.8-1232168.patch @@ -0,0 +1,200 @@ +From 944864e679b37423b0e159d0a6cfc4267e609541 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 28 Jun 2016 16:50:37 -0400 +Subject: [PATCH 59/60] More edits for grubby.8 (#1232168) + +- Don't switch between the passive and active voice between the option + descriptions +- keep the same point of view between options ("[it] removes all + entries" vs "remove all entries") +- line wrap everywhere except the example envocations at <80 columns, + not 100. +- consistent use of i386 vs ia32 + +Signed-off-by: Peter Jones + +Related: rhbz#1232168 +--- + grubby.8 | 82 +++++++++++++++++++++++++++++++++++----------------------------- + 1 file changed, 45 insertions(+), 37 deletions(-) + +diff --git a/grubby.8 b/grubby.8 +index 5e1b521..1197109 100644 +--- a/grubby.8 ++++ b/grubby.8 +@@ -2,11 +2,12 @@ + + .SH NAME + +-grubby \- command line tool used to configure bootloader menu entries across multiple architectures ++grubby \- command line tool used to configure bootloader menu entries across ++multiple architectures + + .SH SYNOPSIS + +-\fBgrubby\fR [\fIOPTIONS...\fR] ++\fBgrubby\fR [\fIOPTIONS\fR] + + .SH DESCRIPTION + +@@ -37,13 +38,13 @@ are deprecated in favor of previously mentioned bootloaders. The + + .SS Default Behavior + +-The default architecture is chosen at compile time. The grubby executable +-has a series of built in assumptions about what bootloader is being used and +-where its configuration file lives. If no output format option is specified +-on the command line then grubby will use these default settings to first +-search for an existing configuration and, if it is not found, assume that +-it should be placed in the standard location. These default assumptions are +-listed in the table below. ++The default bootloader target is primarily determined by the architecture ++for which grubby has been built. Each architecture has a preferred ++bootloader, and each bootloader has its own configuration file. If no ++bootloader is selected on the command line, grubby will use these default ++settings to search for an existing configuration. If no bootloader ++configuration file is found, grubby will use the default value for that ++architecture. These defaults are listed in the table below. + + .TS + allbox; +@@ -81,19 +82,18 @@ Add a new boot entry for the kernel located at \fIkernel-path\fR. A title for + the boot entry must be set using \fB-\-title\fR. Most invocations should also + include \fB-\-initrd\fR with memtest86 as a notable exception. + +-The \fB-\-update-kernel\fR +-option may not be used in the same invocation. ++The \fB-\-update-kernel\fR option may not be used in the same invocation. + + .TP + \fB-\-remove-kernel\fR=\fIkernel-path\fR +-Removes all boot entries which match \fIkernel-path\fR. This may be used +-along with \fB-\-add-kernel\fR, in which case the new kernel being added will +-never be removed. ++Remove all boot entries which match \fIkernel-path\fR. This may be used ++along with \fB-\-add-kernel\fR, in which case the new entry being added will ++not be removed. + + .TP + \fB-\-update-kernel\fR=\fIkernel-path\fR +-The entries for kernels matching \fRkernel-path\fR are updated. Currently +-the only items that can be updated is the kernel argument list, which is ++Update the entries for kernels matching \fRkernel-path\fR. Currently ++the only item that can be updated is the kernel argument list, which is + modified via the \fB-\-args\fR and \fB-\-remove-args\fR options. + + .TP +@@ -135,7 +135,7 @@ being added. + + .TP + \fB-\-efi\fR +-Use linuxefi and initrdefi when constructing bootloader stanzas instead of linux and initrd. ++Use appropriate bootloader commands for EFI on this architecture. + + .TP + \fB-\-set-default\fR=\fIkernel-path\fR +@@ -188,16 +188,18 @@ Display information on all boot entries which match \fIkernel-path\fR. I + + .TP + \fB-\-bootloader-probe\fR ++Attempt to probe for installed bootloaders. If this option is specified, + \fBgrubby\fR tries to determine if \fBgrub\fR or \fBlilo\fR is currently +-installed. When one of those bootloaders is found the name of that bootloader +-is displayed on stdout. Both could be installed (on different devices), and +-grubby will print out the names of both bootloaders, one per line. The probe +-for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR +-identical to the standard directive in the lilo configuration file. If this +-is not present \fBgrubby\fR will assume grub is not installed (note +-that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates). ++installed. When one of those bootloaders is found the name of that ++bootloader is displayed on stdout. Both could be installed (on different ++devices), and grubby will print out the names of both bootloaders, one per ++line. The probe for \fBgrub\fR requires a commented out boot directive ++\fBgrub.conf\fR identical to the standard directive in the lilo ++configuration file. If this is not present \fBgrubby\fR will assume grub is ++not installed (note that \fBanaconda\fR places this directive in ++\fBgrub.conf\fR files it creates). + +-\fIThis option is only available on i386 platforms.\fR ++\fIThis option is only available on x86 BIOS platforms.\fR + + .TP + \fB-v\fR, \fB-\-version\fR +@@ -213,7 +215,8 @@ alternative bootloader. + + .TP + \fB-\-elilo\fR +-Use an \fBelilo\fR style configuration file. This is the default on ia64 platforms. This format is deprecated. ++Use an \fBelilo\fR style configuration file. This is the default on ia64 ++platforms. This format is deprecated. + + .TP + \fB-\-extlinux\fR +@@ -221,13 +224,14 @@ Use an \fBextlinux\fR style configuration file. This format is deprecated. + + .TP + \fB-\-grub\fR +-Use a \fBgrub\fR style configuration file. This is the default on ia32 platforms. ++Use a \fBgrub\fR style configuration file. This is the default on the i386 ++architecture. + + .TP + \fB-\-grub2\fR +-Use a \fBgrub2\fR style configuration file. This is the default on \fBx86_64\fR +-architecture as well as the \fBppc64\fR and \fBppc64le\fR architectures +-running on Power8 or later hardware. ++Use a \fBgrub2\fR style configuration file. This is the default on ++\fBx86_64\fR architecture as well as the \fBppc64\fR and \fBppc64le\fR ++architectures running on Power8 or later hardware. + + .TP + \fB-\-lilo\fR +@@ -235,7 +239,8 @@ Use a \fBlilo\fR style configuration file. + + .TP + \fB-\-silo\fR +-Use a \fBsilo\fR style configuration file. This is the default on SPARC systems. This format is legacy, deprecated, and unsupported. ++Use a \fBsilo\fR style configuration file. This is the default on SPARC ++systems. This format is legacy, deprecated, and unsupported. + + .TP + \fB-\-yaboot\fR +@@ -330,12 +335,13 @@ kernel_args Set of arguments for the kernel + menu_index Index number of a menu entry + .TE + +-The examples below quote strings that may have spaces or other whitespace in them. It is also +-perfectly valid to backslash escape these strings if that is more convenient. ++The examples below quote strings that may have spaces or other whitespace in ++them. It is also perfectly valid to backslash escape these strings if that ++is more convenient. + + .PP +-Add a new kernel entry and copy all options from the current default kernel. This is the behavior +-that most users will want. ++Add a new kernel entry and copy all options from the current default kernel. ++This is the behavior that most users will want. + .IP + \fBgrubby\fR --add-kernel=\fInew_kernel\fR --title="\fIentry_title\fR" --initrd="\fInew_initrd\fR" --copy-default + .PP +@@ -347,13 +353,15 @@ Remove \fBall menu entries\fR for a specified kernel. + .IP + \fBgrubby\fR --remove-kernel=\fIold_kernel\fR + .PP +-Target a single menu entry to remove without targetting other entries with the same kernel. ++Target a single menu entry to remove without targetting other entries with ++the same kernel. + .IP + \fBgrubby\fR --info=\fIold_kernel\fR + + \fBgrubby\fR --remove-kernel=\fImenu_index\fR + .PP +-Update the arguments for all entries of a specific kernel. New arguments get added while existing arguments get updated values. ++Update the arguments for all entries of a specific kernel. New arguments get ++added while existing arguments get updated values. + .IP + \fBgrubby\fR --update-kernel=\fIcurrent_kernel\fR --args="\fIkernel_args\fR" + .PP +-- +2.5.5 + diff --git a/SOURCES/0060-Minor-man-page-changes-1232168.patch b/SOURCES/0060-Minor-man-page-changes-1232168.patch new file mode 100644 index 0000000..1a9eb71 --- /dev/null +++ b/SOURCES/0060-Minor-man-page-changes-1232168.patch @@ -0,0 +1,36 @@ +From 3cb6a97baa11eedc772ea83f8958691bfa3d3c26 Mon Sep 17 00:00:00 2001 +From: Robert Marshall +Date: Fri, 1 Jul 2016 15:24:34 -0400 +Subject: [PATCH 60/60] Minor man page changes (#1232168) + +Minor wording changes made in the Architecture section after placing the +initial draft up for public comment. + +Related: rhbz#1232168 +--- + grubby.8 | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grubby.8 b/grubby.8 +index 1197109..7789b9a 100644 +--- a/grubby.8 ++++ b/grubby.8 +@@ -29,12 +29,12 @@ Legacy \fBs390\fR and the current \fBs390x\fR architectures + and their \fBzipl\fR bootloader are fully supported. + + Support for \fByaboot\fR has been deprecated as all ppc architecture +-hardware since the Power8 system uses \fBgrub2\fR or petitboot ++hardware since the Power8 uses \fBgrub2\fR or petitboot + which both use the grub2 configuration file format. + + Legacy bootloaders \fBLILO\fR, \fBSILO\fR, and \fBELILO\fR +-are deprecated in favor of previously mentioned bootloaders. The +-\fBSILO\fR bootloader should also be considered unsupported. ++are deprecated and no longer receiving active support in favor of ++previously mentioned bootloaders. + + .SS Default Behavior + +-- +2.5.5 + diff --git a/SPECS/grubby.spec b/SPECS/grubby.spec index afc8670..15955ee 100644 --- a/SPECS/grubby.spec +++ b/SPECS/grubby.spec @@ -1,6 +1,6 @@ Name: grubby Version: 8.28 -Release: 17%{?dist} +Release: 18%{?dist} Summary: Command line tool for updating bootloader configs Group: System Environment/Base License: GPLv2+ @@ -47,14 +47,25 @@ Patch0038: 0038-Add-a-bunch-of-tests-for-various-default-kernel-titl.patch Patch0039: 0039-Emit-better-systemd-debug-settings-on-debug-entries.patch Patch0040: 0040-Make-the-grub1-defaultkernel-test-more-reliable.patch Patch0041: 0041-Work-around-aarch64-not-having-quite-the-same-grub-c.patch -Patch0042: 0001-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch -Patch0043: 0001-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch -Patch0044: 0001-Don-t-leak-from-one-extractTitle-call.patch -Patch0045: 0002-Better-formatting.patch -Patch0046: 0003-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch -Patch0047: 0001-Specify-bootloader-directory-in-the-test-case-for-11.patch -Patch0048: 0001-Fix-some-coverity-concerns.patch -Patch0049: 0001-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch +Patch0042: 0042-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch +Patch0043: 0043-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch +Patch0044: 0044-Don-t-leak-from-one-extractTitle-call.patch +Patch0045: 0045-Better-formatting.patch +Patch0046: 0046-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch +Patch0047: 0047-Specify-bootloader-directory-in-the-test-case-for-11.patch +Patch0048: 0048-Fix-some-coverity-concerns.patch +Patch0049: 0049-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch +Patch0050: 0050-grubby-add-set-index-to-specify-which-position-to-ad.patch +Patch0051: 0051-Fix-thinko-on-set-index-naming.patch +Patch0052: 0052-Fix-a-typo-on-the-rhel-7.3-branch.patch +Patch0053: 0053-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch +Patch0054: 0054-Ensure-command-line-updates-also-honor-set-index.patch +Patch0055: 0055-Change-debug-entry-insertion-order-rhbz-1285601.patch +Patch0056: 0056-Reorganize-grubby-man-page-1232168.patch +Patch0057: 0057-Update-grubby-man-page-contents-bz1232168.patch +Patch0058: 0058-Fix-inline-help-typo-1232168.patch +Patch0059: 0059-More-edits-for-grubby.8-1232168.patch +Patch0060: 0060-Minor-man-page-changes-1232168.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: pkgconfig glib2-devel popt-devel @@ -70,6 +81,7 @@ Requires: s390utils-base %ifarch %{arm} Requires: uboot-tools %endif +Requires: system-release %description grubby is a command line tool for updating and displaying information about @@ -125,6 +137,17 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog +* Fri Jul 01 2016 rmarshall@redhat.com - 8.28-18 +- Patched new-kernel-pkg so that kernel installations when MAKEDEBUG is + set would put the debugging entries after the non-debugging entries. + Resolves: #1285601 +- Re-numbered the last set of patches to go with the flow. No actual + changes to the patches; just a git mv to rename. +- Re-organized and updated the grubby man page contents to include some + features that were not documented as well as correct typos and + re-write some entries for better clarity. + Resolves: #1232168 + * Mon Oct 26 2015 Peter Jones - 8.28-17 - Fix the ordering of creating the debug entries, so they don't get picked when we're choosing kernel command line defaults on upgrades.