From c05dcb8a5d5c7ab510b561dfd37bb846fdcd6b0c Mon Sep 17 00:00:00 2001
From: Nathan Yee <nyee32@schedmd.com>
Date: Thu, 24 Sep 2015 13:50:07 -0700
Subject: [PATCH] Modify node list parsing to take expressions

Modify the slurm_addto_char_list to process hostlist expressions
 rather than only a comma-delimited list of host names. This
 effects sreport, sacctmgr, and other commands
bug 1923
---
 src/common/slurm_protocol_defs.c | 165 +++++++++++++++++++++----------
 1 file changed, 112 insertions(+), 53 deletions(-)

diff --git a/src/common/slurm_protocol_defs.c b/src/common/slurm_protocol_defs.c
index 3d474d826db..8e66e78d2f0 100644
--- a/src/common/slurm_protocol_defs.c
+++ b/src/common/slurm_protocol_defs.c
@@ -188,16 +188,31 @@ extern List slurm_copy_char_list(List char_list)
 	return ret_list;
 }
 
+static int _find_char_in_list(void *x, void *key)
+{
+	char *char1 = (char *)x;
+	char *char2 = (char *)key;
+
+	if (!strcasecmp(char1, char2))
+		return 1;
+
+	return 0;
+}
+
 
 /* returns number of objects added to list */
 extern int slurm_addto_char_list(List char_list, char *names)
 {
-	int i=0, start=0;
-	char *name = NULL, *tmp_char = NULL;
+	int i = 0, start = 0;
+	char *name = NULL;
 	ListIterator itr = NULL;
 	char quote_c = '\0';
 	int quote = 0;
 	int count = 0;
+	bool brack_not = false;
+	bool first_brack = false;
+	char *this_node_name;
+	hostlist_t host_list;
 
 	if (!char_list) {
 		error("No list was given to fill in");
@@ -218,69 +233,113 @@ extern int slurm_addto_char_list(List char_list, char *names)
 				break;
 			else if ((names[i] == '\"') || (names[i] == '\''))
 				names[i] = '`';
-			else if (names[i] == ',') {
-				/* If there is a comma at the end just
-				   ignore it */
-				if (!names[i+1])
-					break;
+			else if (names[i] == '[')
+			       /* Make sure there is a open bracket. This
+				* check is to allow comma sperated notation
+				* within the bracket ie. linux[0-1,2]  */
+				first_brack = true;
+			else if (names[i] == ',' && !first_brack) {
+				/* Check that the string before , was
+				 * not a [] notation value */
+				if (!brack_not) {
+					/* If there is a comma at the end just
+					 * ignore it */
+					if (!names[i+1])
+						break;
 
-				name = xstrndup(names+start, (i-start));
+					name = xstrndup(names+start,
+							(i-start));
+					//info("got %s %d", name, i-start);
+
+					/* If we get a duplicate remove the
+					 * first one and tack this on the end.
+					 * This is needed for get associations
+					 * with qos.
+					 */
+					if (list_find(itr,
+						      _find_char_in_list,
+						      name)) {
+						list_delete_item(itr);
+					} else
+						count++;
+
+					xstrtolower(name);
+					list_append(char_list, name);
+
+					list_iterator_reset(itr);
+
+					i++;
+					start = i;
+					if (!names[i]) {
+						info("There is a problem "
+						     "with your request. "
+						     "It appears you have "
+						     "spaces inside your "
+						     "list.");
+						count = 0;
+						goto endit;
+					}
+				} else {
+					brack_not = false;
+					/* Skip over the , so it is
+					 * not included in the char list */
+					start = ++i;
+				}
+			} else if (names[i] == ']') {
+				brack_not = true;
+				first_brack = false;
+				name = xstrndup(names+start, ((i + 1)-start));
 				//info("got %s %d", name, i-start);
 
-				while ((tmp_char = list_next(itr))) {
-					if (!strcasecmp(tmp_char, name))
-						break;
-				}
-				/* If we get a duplicate remove the
-				 * first one and tack this on the end.
-				 * This is needed for get associations
-				 * with qos.
-				 */
-				if (tmp_char)
-					list_delete_item(itr);
-				else
-					count++;
-
-				xstrtolower(name);
-				list_append(char_list, name);
-
-				list_iterator_reset(itr);
-
-				i++;
-				start = i;
-				if (!names[i]) {
-					info("There is a problem with "
-					     "your request.  It appears you "
-					     "have spaces inside your list.");
-					count = 0;
-					goto endit;
+				if ((host_list = hostlist_create(name))) {
+					while ((this_node_name =
+						xstrdup(hostlist_shift
+							(host_list)))) {
+						/* If we get a duplicate
+						 * remove the first one and tack
+						 * this on the end. This is
+						 * needed for get associations
+						 * with qos.
+						 */
+						if (list_find(itr,
+							    _find_char_in_list,
+							    this_node_name)) {
+							list_delete_item(itr);
+						} else
+							count++;
+
+						xstrtolower(this_node_name);
+						list_append(char_list,
+							    this_node_name);
+
+						list_iterator_reset(itr);
+
+						start = i + 1;
+					}
 				}
+				hostlist_destroy(host_list);
 			}
 			i++;
 		}
 
-		name = xstrndup(names+start, (i-start));
-		while ((tmp_char = list_next(itr))) {
-			if (!strcasecmp(tmp_char, name))
-				break;
+		if (i-start) {
+			name = xstrndup(names+start, (i-start));
+			/* If we get a duplicate remove the
+			 * first one and tack this on the end.
+			 * This is needed for get associations
+			 * with qos.
+			 */
+			if (list_find(itr, _find_char_in_list, name)) {
+				list_delete_item(itr);
+			} else
+				count++;
+
+			xstrtolower(name);
+			list_append(char_list, name);
 		}
-
-		/* If we get a duplicate remove the
-		 * first one and tack this on the end.
-		 * This is needed for get associations
-		 * with qos.
-		 */
-		if (tmp_char)
-			list_delete_item(itr);
-		else
-			count++;
-
-		xstrtolower(name);
-		list_append(char_list, name);
 	}
 endit:
 	list_iterator_destroy(itr);
-
 	return count;
 }
 
-- 
GitLab