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