From 9a91ef772cb72856704b89ff83c9db71196081c1 Mon Sep 17 00:00:00 2001
From: Modestas Vainius <modax@debian.org>
Date: Mon, 6 Dec 2010 12:05:34 +0200
Subject: [PATCH] dmraid-active: handle the case DDF1 virtual drive has a name.

Further improve dmraid-activate DDF1 awk snippet to handle the case when
virtual drive (VD) has a human-readable name. In that case, dmraid will use
that name instead of the VD GUID when generating a device for the respective
raid subset.

Since human-readable names might contain spaces, make appropriate (but ugly
looking) tweaks to IFS variable as needed. We can't use `while read` since that
would fork a new shell and make global variables unavailable for
activate_array().
---
 debian/dmraid-activate |  113 +++++++++++++++++++++++++++++++++++++----------
 1 files changed, 89 insertions(+), 24 deletions(-)

diff --git a/debian/dmraid-activate b/debian/dmraid-activate
index 7e73473..f420289 100644
--- a/debian/dmraid-activate
+++ b/debian/dmraid-activate
@@ -116,13 +116,18 @@ log_error()
 	fi
 }
 
-ddf1_virtual_drive_guids()
+ddf1_virtual_drive_names()
 {
-	ddf1_awk_script=$(cat <<'EOF'
+	ddf1_awk_script="$(cat <<'EOF'
 BEGIN {
     section = ""
     disk_ref = ""
     guid_i = 0
+
+    # Heximal to decimal conversion array
+    for (i = 0; i <= 9; i++) hex2dec[i] = i
+    hex2dec["a"] = 10; hex2dec["b"] = 11; hex2dec["c"] = 12
+    hex2dec["e"] = 13; hex2dec["d"] = 14; hex2dec["f"] = 15;
 }
 
 function section_begins(name)
@@ -132,6 +137,42 @@ function section_begins(name)
     drive_map = 0
 }
 
+function extract_vd_guid(line,      g)
+{
+    g = substr(line, match(line,/\[[0-9a-f ]+\]$/)+1, RLENGTH-2)
+    gsub(/ /, "", g)
+    # IF LSI, do timestamp substitution to get persistent name, see
+    # 19_ddf1_lsi_persistent_name.patch
+    if (g ~ /^4c5349/)
+        g = substr(g, 1, 32) "47114711" substr(g, 41)
+    return g
+}
+
+function extract_vd_name(line,     hex, n, max, i, d1, d2, sed)
+{
+    n = tolower(substr(line, match(line,/\[[0-9a-f ]+\]$/)+1, RLENGTH-2))
+    max = split(n, hex, / /)
+
+    if (max <= 0 || hex[0] == "00") return ""
+
+    # Convert name from hex to string (16 bytes)
+    n = ""
+    for (i = 1; i <= max; i++) {
+        d1 = hex2dec[substr(hex[i], 1, 1)]
+        d2 = hex2dec[substr(hex[i], 2, 1)]
+        if ((d1 + d2) == 0) break
+        n = n sprintf("%c", d1 * 16 + d2)
+    }
+    # Shell-escape single quotes in the name
+    gsub(/'/,"'\\''", n)
+    # Finally strip non-graph chars from the end of the string
+    # mawk does not support character classes. Use sed.
+    sed = "echo '" n "' | sed 's/[^[:graph:]]\+$//'"
+    sed | getline n
+    close(sed)
+    return n
+}
+
 {
     if (!/^0x/ && / at /) {
         # Section begins
@@ -140,31 +181,45 @@ function section_begins(name)
         disk_ref = $3
         sub(/^0x/, "", disk_ref)
     } else if (disk_ref) {
-        if (section == "Virtual Drive Config Record" && /^0x008 guid:/) {
-            vd_guid = substr($0, match($0,/\[[0-9a-f ]+\]$/)+1, RLENGTH-2)
-            gsub(/ /, "", vd_guid)
-            # IF LSI, do timestamp substitution to get persistent name, see
-            # 19_ddf1_lsi_persistent_name.patch
-            if (vd_guid ~ /^4c5349/)
-                vd_guid = substr(vd_guid, 1, 32) "47114711" substr(vd_guid, 41)
-        } else if (drive_map) {
-            # 0: 4BCBB980 @ 0
-            if ($2 == disk_ref) {
-                guids[guid_i] = vd_guid
-                guid_i++
+        # We need to parse 'Virtual Drive' sections in order to extract VD
+        # names
+        if (section == "Virtual Drive") {
+            if (/^0x000 guid:/) {
+                vd_guid = extract_vd_guid($0)
+            } else if (/^0x030 name:/) {
+                vd_name = extract_vd_name($0)
+                if (vd_name)
+                    vd_names[vd_guid] = vd_name
+            }
+        } else if (section == "Virtual Drive Config Record") {
+            if (/^0x008 guid:/) {
+                vd_guid = extract_vd_guid($0)
+            } else if (drive_map) {
+                # 0: 4BCBB980 @ 0
+                if ($2 == disk_ref) {
+                    guids[guid_i] = vd_guid
+                    guid_i++
+                }
+            } else if (vd_guid) {
+                drive_map = /^Drive map:/
             }
-        } else if (vd_guid) {
-            drive_map = /^Drive map:/
         }
     }
 }
 END {
-    # Print discovered virtual drive GUIDs which belong to this physical drive
-    for (guid in guids)
-        print guids[guid]
+    # Print discovered virtual drive names (or GUIDs) which belong to this
+    # physical drive
+    for (guid_i in guids) {
+        guid = guids[guid_i]
+        if (guid in vd_names) {
+            print vd_names[guid]
+        } else {
+            print guid
+        }
+    }
 }
 EOF
-)
+)"
 	dmraid -i -n "$1" | awk "$ddf1_awk_script"
 }
 
@@ -193,6 +248,9 @@ if [ -z "$Raid_Name" ]; then
 	exit 0
 fi
 
+newline="
+"
+
 case "$Raid_Name" in
 	isw_*)
 		# We need a special case for isw arrays, since it is possible to have several
@@ -208,13 +266,20 @@ case "$Raid_Name" in
 		;;
 	.ddf1_disks)
 		# Dummy name for the main DDF1 group. Needs special handling to
-		# find RAID subsets for this physical drive
-		Ddf1_guids=`ddf1_virtual_drive_guids "/dev/$Node_Name"`
+		# find RAID subsets (name or GUID) for this physical drive
+		Ddf1_names=`ddf1_virtual_drive_names "/dev/$Node_Name"`
 
-		for ddf1_guid in $Ddf1_guids
+		# Returned names might contain space characters. Therefore
+		# split fields at new line. Use $IFS to avoid forking a new shell
+		save_IFS="$IFS"
+		IFS="$newline"
+		for ddf1_name in $Ddf1_names
 		do
-			activate_array "ddf1_${ddf1_guid}"
+			IFS="$save_IFS"
+			activate_array "ddf1_${ddf1_name}"
+			IFS="$newline"
 		done
+		IFS="$save_IFS"
 		break
 		;;
 	*)
-- 
1.7.2.3

