[Rear-users] SF.net SVN: rear:[741] trunk/usr/share/rear/layout/save/GNU/Linux/ 20_partition_layout.sh

jhoekx at users.sourceforge.net jhoekx at users.sourceforge.net
Wed Nov 23 16:25:48 CET 2011


Revision: 741
          http://rear.svn.sourceforge.net/rear/?rev=741&view=rev
Author:   jhoekx
Date:     2011-11-23 15:25:47 +0000 (Wed, 23 Nov 2011)
Log Message:
-----------
layout: improve partition detection code.

 - Use machine readable parted output if available.
 - Made a function out of it, so multipath and raid devices can reuse the same code.

The machine readable parted output does not include the partition type, so this is now scripted and uses sfdisk or parted flags.

Modified Paths:
--------------
    trunk/usr/share/rear/layout/save/GNU/Linux/20_partition_layout.sh

Modified: trunk/usr/share/rear/layout/save/GNU/Linux/20_partition_layout.sh
===================================================================
--- trunk/usr/share/rear/layout/save/GNU/Linux/20_partition_layout.sh	2011-11-23 14:22:14 UTC (rev 740)
+++ trunk/usr/share/rear/layout/save/GNU/Linux/20_partition_layout.sh	2011-11-23 15:25:47 UTC (rev 741)
@@ -1,119 +1,203 @@
 # Save the partition layout
 
-Log "Saving disk partitions."
+### Parted can output machine parseable information
+FEATURE_PARTED_MACHINEREADABLE=
+### Parted used to have slightly different naming
+FEATURE_PARTED_OLDNAMING=
 
-(
-    # Disk sizes
-    # format: disk <disk> <sectors> <partition label type>
-    devices=()
-    for disk in /sys/block/* ; do
-        case $(basename $disk) in
-            hd*|sd*|cciss*|vd*)
-                devname=$(get_device_name $disk)
-                devsize=$(get_disk_size ${disk#/sys/block/})
+parted_version=$(get_version parted -v)
+[[ "$parted_version" ]]
+BugIfError "Function get_version could not detect parted version."
 
-                disktype=$(parted -s /dev/$devname print | grep -E "Partition Table|Disk label" | cut -d ":" -f "2" | tr -d " ")
+if version_newer "$parted_version" 1.8.2 ; then
+    FEATURE_PARTED_MACHINEREADABLE=y
+fi
+if ! version_newer "$parted_version" 1.6.23 ; then
+    FEATURE_PARTED_OLDNAMING=y
+fi
 
-                echo "disk /dev/$devname $devsize $disktype"
+# Extract partitioning information of device $1 (full device path)
+# format : part <partition size(bytes)> <partition start(bytes)> <partition type|name> <flags> /dev/<partition>
+extract_partitions() {
+    declare device=$1
 
-                devices=( "${devices[@]}" "$devname" )
-                ;;
-        esac
+    declare sysfs_name=$(get_sysfs_name $device)
+    declare block_size=$(get_block_size $device)
+
+    ### collect basic information
+    : > $TMP_DIR/partitions
+
+    declare path partition_name partition_prefix start_block
+    declare partition_nr size start
+    for path in /sys/block/$sysfs_name/$sysfs_name* ; do
+        partition_name=${path##*/}
+
+        [[ $partition_name =~ ([0-9]+)$ ]]
+        partition_nr=${BASH_REMATCH[1]}
+
+        partition_prefix=${partition_name%$partition_nr}
+
+        size=$(get_disk_size $sysfs_name/$partition_name)
+        start_block=$(< $path/start)
+        if [[ -z "$start_block" ]] ; then
+            BugError "Could not determine start of partition $partition_name, please file a bug."
+        fi
+        start=$(( $start_block*$block_size ))
+
+        echo "$partition_nr $size $start">> $TMP_DIR/partitions
     done
 
-    # This uses parted. Old versions of parted produce different output than newer versions.
-    parted_version=$(get_version parted -v)
-    [ "$parted_version" ]
-    BugIfError "Function get_version could not detect parted version."
+    if [[ ! -s $TMP_DIR/partitions ]] ; then
+        Debug "No partitions found on $device."
+        return
+    fi
 
-    if ! version_newer "$parted_version" 1.6.23 ; then
-        oldparted="yes"
-        Log "Old version of parted detected."
+    ### Cache parted data
+    declare disk_label
+    if [[ $FEATURE_PARTED_MACHINEREADABLE ]] ; then
+        parted -m -s $device print > $TMP_DIR/parted
+        disk_label=$(grep ^/ $TMP_DIR/parted | cut -d ":" -f "6")
+    else
+        parted -s $device print > $TMP_DIR/parted
+        disk_label=$(grep -E "Partition Table|Disk label" $TMP_DIR/parted | cut -d ":" -f "2" | tr -d " ")
     fi
 
-    # Partitions
-    # Partitions are read from sysfs. Extra information is collected using parted
-    # format : part <partition size(bytes)> <partition type|name> <flags> /dev/<partition>
-    for device in "${devices[@]}" ; do
-        if [ -e /dev/$device ] ; then
+    cp $TMP_DIR/partitions $TMP_DIR/partitions-data
 
-            sysfsname=$(get_sysfs_name $device)
-            blocksize=$(get_block_size $sysfsname)
+    declare type
 
-            # Check for old version of parted.
-            # Parted on RHEL 4 outputs differently
-            # - header names: minor instead of number,
-            # - no support for units (we use sysfs for sizes)
-            if [ -z "$oldparted" ] ; then
-                numberfield="number"
+    ### determine partition type for msdos partition tables
+    if [[ "$disk_label" = "msdos" ]] ; then
+        declare -i has_logical
+        while read partition_nr size start junk ; do
+            if (( $partition_nr > 4 )) ; then
+                ### logical
+                has_logical=1
+                sed -i /^$partition_nr\ /s/$/\ logical/ $TMP_DIR/partitions
             else
-                numberfield="minor"
+                ### set to primary until flags are known
+                declare type="primary"
+                sed -i /^$partition_nr\ /s/$/\ primary/ $TMP_DIR/partitions
             fi
+        done < $TMP_DIR/partitions-data
+    fi
 
-            parted -s /dev/$device print > $TMP_DIR/parted
-            disktype=$(grep -E "Partition Table|Disk label" $TMP_DIR/parted | cut -d ":" -f "2" | tr -d " ")
-
-            # Difference between gpt and msdos: type|name
-            case $disktype in
-                msdos)
-                    typefield="type"
-                    ;;
-                gpt)
-                    typefield="name"
-                    ;;
-                *)
-                    Log "Unsupported disk label $disktype on $device."
-                    continue
-            esac
-
+    ### find partition name for gpt disks.
+    if [[ "$disk_label" = "gpt" ]] ; then
+        if [[ "$FEATURE_PARTED_MACHINEREADABLE" ]] ; then
+            while read partition_nr size start junk ; do
+                type=$(grep "^$partition_nr:" $TMP_DIR/parted | cut -d ":" -f "6")
+                if [[ -z "$type" ]] ; then
+                    type="rear-noname"
+                fi
+                sed -i /^$partition_nr\ /s/$/\ $type/ $TMP_DIR/partitions
+            done < $TMP_DIR/partitions-data
+        else
+            declare line line_length number numberfield
             init_columns "$(grep "Flags" $TMP_DIR/parted)"
             while read line ; do
                 # read throws away leading spaces
-                number=${line%% *}
-                if [ "$number" -lt 10 ] ; then
+                line_length=${line%% *}
+                if (( "$line_length" < 10 )) ; then
                     line=" $line"
                 fi
 
-                pnumber=$(get_columns "$line" "$numberfield" | tr -d " " | tr -d ";")
-                ptype=$(get_columns "$line" "$typefield" | tr -d " " | tr -d ";")
-                pflags=$(get_columns "$line" "flags" | tr -d "," |tr -d ";")
+                if [[ "$FEATURE_PARTED_OLDNAMING" ]] ; then
+                    numberfield="minor"
+                else
+                    numberfield="number"
+                fi
 
-                if [ -z "$ptype" ] ; then
-                    ptype="rear-noname"
+                number=$(get_columns "$line" "$numberfield" | tr -d " " | tr -d ";")
+                type=$(get_columns "$line" "name" | tr -d " " | tr -d ";")
+
+                if [[ -z "$type" ]] ; then
+                    type="rear-noname"
                 fi
 
-                case $device in
-                    *cciss*)
-                        pname="p${pnumber}"
-                        ;;
-                    *)
-                        pname="${pnumber}"
-                        ;;
-                esac
+                sed -i /^$number\ /s/$/\ $type/ $TMP_DIR/partitions
+            done < <(grep -E '^[ ]*[0-9]' $TMP_DIR/parted)
+        fi
+    fi
 
-                psize=$(get_disk_size "$sysfsname/$sysfsname$pname")
+    ### find the flags given by parted.
+    declare flags
+    if [[ "$FEATURE_PARTED_MACHINEREADABLE" ]] ; then
+        while read partition_nr size start junk ; do
+            flags=$(grep "^$partition_nr:" $TMP_DIR/parted | cut -d ":" -f "7" | tr -d " " | tr -d ";")
+            if [[ -z "$flags" ]] ; then
+                flags="none"
+            fi
+            sed -i /^$partition_nr\ /s/$/\ $flags/ $TMP_DIR/partitions
+        done < $TMP_DIR/partitions-data
+    else
+        declare line line_length number numberfield
+        init_columns "$(grep "Flags" $TMP_DIR/parted)"
+        while read line ; do
+            # read throws away leading spaces
+            line_length=${line%% *}
+            if (( "$line_length" < 10 )) ; then
+                line=" $line"
+            fi
 
-                pstart=$( < /sys/block/$sysfsname/${sysfsname}${pname}/start)
-                if [ -z "$pstart" ] ; then
-                    BugError "Could not determine start of partition ${sysfsname}${pname}, please file a bug."
-                fi
-                let pstart=$pstart\*$blocksize
+            if [[ "$FEATURE_PARTED_OLDNAMING" ]] ; then
+                numberfield="minor"
+            else
+                numberfield="number"
+            fi
 
-                flags=""
-                for flag in $pflags ; do
-                    case $flag in
-                        boot|root|swap|hidden|raid|lvm|lba|palo|legacy_boot|bios_grub)
-                            flags="$flags$flag,"
-                            ;;
-                    esac
-                done
-                if [ -z "$flags" ] ; then
-                    flags="none"
+            number=$(get_columns "$line" "$numberfield" | tr -d " " | tr -d ";")
+            flags=$(get_columns "$line" "flags" | tr -d " " | tr -d ";")
+
+            if [[ -z "$flags" ]] ; then
+                flags="none"
+            fi
+
+            sed -i /^$number\ /s/$/\ $flags/ $TMP_DIR/partitions
+        done < <(grep -E '^[ ]*[0-9]' $TMP_DIR/parted)
+    fi
+
+    ### Find an extended partition if there is one
+    if [[ "$disk_label" = "msdos" ]] && [[ "$has_logical" ]] ; then
+        cp $TMP_DIR/partitions $TMP_DIR/partitions-data
+        while read partition_nr size start type flags junk ; do
+            (( $partition_nr > 4 )) && continue
+
+            if has_binary sfdisk ; then
+                declare partition_id=$(sfdisk -c $device $partition_nr)
+                if [[ "$partition_id" = "f" ]] || [[ "$partition_id" = "5" ]] ; then
+                    sed -i /^$partition_nr\ /s/\ primary\ /\ extended\ / $TMP_DIR/partitions
                 fi
+            else
+                if [[ "${flags/lba/}" != "$flags" ]] ; then
+                    sed -i /^$partition_nr\ /s/\ primary\ /\ extended\ / $TMP_DIR/partitions
+                fi
+            fi
+        done < $TMP_DIR/partitions-data
+    fi
 
-                echo "part /dev/$device $psize $pstart $ptype ${flags%,} /dev/${device}${pname}"
-            done < <(grep -E '^[ ]*[0-9]' $TMP_DIR/parted)
+    ### Write to layout file
+    while read partition_nr size start type flags junk ; do
+        echo "part $device $size $start $type $flags ${device%/*}/${partition_prefix/\!//}$partition_nr"
+    done < $TMP_DIR/partitions
+}
 
+
+Log "Saving disk partitions."
+
+(
+    # Disk sizes
+    # format: disk <disk> <sectors> <partition label type>
+    for disk in /sys/block/* ; do
+        if [[ ${disk#/sys/block/} = @(hd*|sd*|cciss*|vd*) ]] ; then
+            devname=$(get_device_name $disk)
+            devsize=$(get_disk_size ${disk#/sys/block/})
+
+            disktype=$(parted -s /dev/$devname print | grep -E "Partition Table|Disk label" | cut -d ":" -f "2" | tr -d " ")
+
+            echo "disk /dev/$devname $devsize $disktype"
+
+            extract_partitions "/dev/$devname"
         fi
     done
 

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.





More information about the rear-users mailing list