|
|
56d25d |
From 280f1ed9a0066cb508d77fe6d072c7c5aa772967 Mon Sep 17 00:00:00 2001
|
|
|
56d25d |
From: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
|
|
|
56d25d |
Date: Tue, 16 Jun 2015 10:43:21 -0700
|
|
|
56d25d |
Subject: [PATCH 35/41] grubby: properly handle mixed ' and " and nested quotes
|
|
|
56d25d |
|
|
|
56d25d |
The SLES12 grub2.cfg file on ppc64le by default contains a line like:
|
|
|
56d25d |
|
|
|
56d25d |
submenu "Bootable snapshot #$snapshot_num" {
|
|
|
56d25d |
menuentry "If OK, run 'snapper rollback $snapshot_num' reboot." { true; }
|
|
|
56d25d |
}
|
|
|
56d25d |
|
|
|
56d25d |
On any grubby (tested with 8.40) invocation that updates the config
|
|
|
56d25d |
file, the combination of nested quotes and mixed quotes leads to a
|
|
|
56d25d |
generated file content like:
|
|
|
56d25d |
|
|
|
56d25d |
submenu "Bootable snapshot #$snapshot_num" {
|
|
|
56d25d |
menuentry 'If OK, run snapper rollback $snapshot_num' rollback $snapshot_num' and reboot." { true; }
|
|
|
56d25d |
}
|
|
|
56d25d |
|
|
|
56d25d |
which includes both a change from " to ', but also improperly quoted
|
|
|
56d25d |
strings and trailing characters relative to the string. This actually
|
|
|
56d25d |
leads to a failure to boot from the disk by default when using grubby
|
|
|
56d25d |
(e.g., Autotest) on SLES12 ppc64le. Whether SLES12 should be adding an
|
|
|
56d25d |
entry like this by default or not is probably open to debate, but grubby
|
|
|
56d25d |
should be able to hand this input file.
|
|
|
56d25d |
|
|
|
56d25d |
To fix the issue, three changes were necessary:
|
|
|
56d25d |
|
|
|
56d25d |
1) grub2ExtractTitle needs to check that if the second element starts
|
|
|
56d25d |
with a quote, that the matching element found ends with the same
|
|
|
56d25d |
quote-type (' vs. ")
|
|
|
56d25d |
|
|
|
56d25d |
2) lineWrite needs to output the right kind of quote based upon if the
|
|
|
56d25d |
string to be outputted itself contains quotes. This is not currently
|
|
|
56d25d |
possible in the code, because quotes are stripped out normally by
|
|
|
56d25d |
readConfig, but with the change in 3), that only happens now for the
|
|
|
56d25d |
quotes that actually delineate a string.
|
|
|
56d25d |
|
|
|
56d25d |
3) readConfig needs to check that when it is extracting titles and
|
|
|
56d25d |
determining extras, it uses matching quotes.
|
|
|
56d25d |
|
|
|
56d25d |
With these changes, a simple grubby --set-default=SLES12 (for example),
|
|
|
56d25d |
now produces:
|
|
|
56d25d |
|
|
|
56d25d |
submenu "Bootable snapshot #$snapshot_num" {
|
|
|
56d25d |
menuentry "If OK, run 'snapper rollback $snapshot_num' and reboot." { true; }
|
|
|
56d25d |
}
|
|
|
56d25d |
|
|
|
56d25d |
as expected.
|
|
|
56d25d |
|
|
|
56d25d |
Signed-off-by: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
|
|
|
56d25d |
---
|
|
|
56d25d |
grubby.c | 42 +++++++++++++++++++++++++++++++++---------
|
|
|
56d25d |
1 file changed, 33 insertions(+), 9 deletions(-)
|
|
|
56d25d |
|
|
|
56d25d |
diff --git a/grubby.c b/grubby.c
|
|
|
56d25d |
index 232704a..407c65d 100644
|
|
|
56d25d |
--- a/grubby.c
|
|
|
56d25d |
+++ b/grubby.c
|
|
|
56d25d |
@@ -446,6 +446,8 @@ char *grub2ExtractTitle(struct singleLine * line) {
|
|
|
56d25d |
* whose last character is also quote (assuming it's the closing one) */
|
|
|
56d25d |
int resultMaxSize;
|
|
|
56d25d |
char * result;
|
|
|
56d25d |
+ /* need to ensure that ' does not match " as we search */
|
|
|
56d25d |
+ char quote_char = *current;
|
|
|
56d25d |
|
|
|
56d25d |
resultMaxSize = sizeOfSingleLine(line);
|
|
|
56d25d |
result = malloc(resultMaxSize);
|
|
|
56d25d |
@@ -459,7 +461,7 @@ char *grub2ExtractTitle(struct singleLine * line) {
|
|
|
56d25d |
current_indent_len = strlen(current_indent);
|
|
|
56d25d |
|
|
|
56d25d |
strncat(result, current_indent, current_indent_len);
|
|
|
56d25d |
- if (!isquote(current[current_len-1])) {
|
|
|
56d25d |
+ if (current[current_len-1] != quote_char) {
|
|
|
56d25d |
strncat(result, current, current_len);
|
|
|
56d25d |
} else {
|
|
|
56d25d |
strncat(result, current, current_len - 1);
|
|
|
56d25d |
@@ -921,10 +923,23 @@ static int lineWrite(FILE * out, struct singleLine * line,
|
|
|
56d25d |
/* Need to handle this, because we strip the quotes from
|
|
|
56d25d |
* menuentry when read it. */
|
|
|
56d25d |
if (line->type == LT_MENUENTRY && i == 1) {
|
|
|
56d25d |
- if(!isquote(*line->elements[i].item))
|
|
|
56d25d |
- fprintf(out, "\'%s\'", line->elements[i].item);
|
|
|
56d25d |
- else
|
|
|
56d25d |
+ if(!isquote(*line->elements[i].item)) {
|
|
|
56d25d |
+ int substring = 0;
|
|
|
56d25d |
+ /* If the line contains nested quotes, we did not strip
|
|
|
56d25d |
+ * the "interna" quotes and we must use the right quotes
|
|
|
56d25d |
+ * again when writing the updated file. */
|
|
|
56d25d |
+ for (int j = i; j < line->numElements; j++) {
|
|
|
56d25d |
+ if (strchr(line->elements[i].item, '\'') != NULL) {
|
|
|
56d25d |
+ substring = 1;
|
|
|
56d25d |
+ fprintf(out, "\"%s\"", line->elements[i].item);
|
|
|
56d25d |
+ break;
|
|
|
56d25d |
+ }
|
|
|
56d25d |
+ }
|
|
|
56d25d |
+ if (!substring)
|
|
|
56d25d |
+ fprintf(out, "\'%s\'", line->elements[i].item);
|
|
|
56d25d |
+ } else {
|
|
|
56d25d |
fprintf(out, "%s", line->elements[i].item);
|
|
|
56d25d |
+ }
|
|
|
56d25d |
fprintf(out, "%s", line->elements[i].indent);
|
|
|
56d25d |
|
|
|
56d25d |
continue;
|
|
|
56d25d |
@@ -1260,6 +1275,8 @@ static struct grubConfig * readConfig(const char * inName,
|
|
|
56d25d |
len = 0;
|
|
|
56d25d |
char *extras;
|
|
|
56d25d |
char *title;
|
|
|
56d25d |
+ /* initially unseen value */
|
|
|
56d25d |
+ char quote_char = '\0';
|
|
|
56d25d |
|
|
|
56d25d |
for (int i = 1; i < line->numElements; i++) {
|
|
|
56d25d |
len += strlen(line->elements[i].item);
|
|
|
56d25d |
@@ -1276,13 +1293,16 @@ static struct grubConfig * readConfig(const char * inName,
|
|
|
56d25d |
for (int i = 0; i < line->numElements; i++) {
|
|
|
56d25d |
if (!strcmp(line->elements[i].item, "menuentry"))
|
|
|
56d25d |
continue;
|
|
|
56d25d |
- if (isquote(*line->elements[i].item))
|
|
|
56d25d |
+ if (isquote(*line->elements[i].item) && quote_char == '\0') {
|
|
|
56d25d |
+ /* ensure we properly pair off quotes */
|
|
|
56d25d |
+ quote_char = *line->elements[i].item;
|
|
|
56d25d |
title = line->elements[i].item + 1;
|
|
|
56d25d |
- else
|
|
|
56d25d |
+ } else {
|
|
|
56d25d |
title = line->elements[i].item;
|
|
|
56d25d |
+ }
|
|
|
56d25d |
|
|
|
56d25d |
len = strlen(title);
|
|
|
56d25d |
- if (isquote(title[len-1])) {
|
|
|
56d25d |
+ if (title[len-1] == quote_char) {
|
|
|
56d25d |
strncat(buf, title,len-1);
|
|
|
56d25d |
break;
|
|
|
56d25d |
} else {
|
|
|
56d25d |
@@ -1293,6 +1313,7 @@ static struct grubConfig * readConfig(const char * inName,
|
|
|
56d25d |
|
|
|
56d25d |
/* get extras */
|
|
|
56d25d |
int count = 0;
|
|
|
56d25d |
+ quote_char = '\0';
|
|
|
56d25d |
for (int i = 0; i < line->numElements; i++) {
|
|
|
56d25d |
if (count >= 2) {
|
|
|
56d25d |
strcat(extras, line->elements[i].item);
|
|
|
56d25d |
@@ -1303,12 +1324,15 @@ static struct grubConfig * readConfig(const char * inName,
|
|
|
56d25d |
continue;
|
|
|
56d25d |
|
|
|
56d25d |
/* count ' or ", there should be two in menuentry line. */
|
|
|
56d25d |
- if (isquote(*line->elements[i].item))
|
|
|
56d25d |
+ if (isquote(*line->elements[i].item) && quote_char == '\0') {
|
|
|
56d25d |
+ /* ensure we properly pair off quotes */
|
|
|
56d25d |
+ quote_char = *line->elements[i].item;
|
|
|
56d25d |
count++;
|
|
|
56d25d |
+ }
|
|
|
56d25d |
|
|
|
56d25d |
len = strlen(line->elements[i].item);
|
|
|
56d25d |
|
|
|
56d25d |
- if (isquote(line->elements[i].item[len -1]))
|
|
|
56d25d |
+ if (line->elements[i].item[len -1] == quote_char)
|
|
|
56d25d |
count++;
|
|
|
56d25d |
|
|
|
56d25d |
/* ok, we get the final ' or ", others are extras. */
|
|
|
56d25d |
--
|
|
|
56d25d |
2.4.3
|
|
|
56d25d |
|