Blame SOURCES/0035-grubby-properly-handle-mixed-and-and-nested-quotes.patch

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