Add swap partition if SWAP property is defined
authorNikos Skalkotos <skalkoto@grnet.gr>
Wed, 9 May 2012 16:01:23 +0000 (19:01 +0300)
committerNikos Skalkotos <skalkoto@grnet.gr>
Wed, 9 May 2012 16:01:23 +0000 (19:01 +0300)
snf-image-helper/common.sh
snf-image-helper/snf-image-helper.in
snf-image-helper/tasks/10FixPartitionTable.in
snf-image-helper/tasks/20FilesystemResizeUnmounted.in
snf-image-helper/tasks/50FilesystemResizeMounted.in

index cbe4eca..ec10768 100644 (file)
@@ -95,12 +95,36 @@ get_distro() {
     fi
 }
 
-get_partition_table() {
+normalize_unit() {
+    unit=$(tr [a-z] [A-Z] <<< $1)
+
+    case $unit in
+        "S") echo "s";;
+        "B"|"") echo "B";;
+        "KB") echo "kB";;
+        "MB") echo "MB";;
+        "GB") echo "GB";;
+        *)  log_error "Unknown unit type: \`$1'";;
+    esac
+}
+
+get_last_partition_id() {
     local dev="$1"
     if ! output="$("$PARTED" -s -m "$dev" print)"; then
         log_error "Unable to read partition table for device \`${dev}'"
     fi
 
+    last_line=$(tail -1 <<< "$output")
+
+    echo $(cut -d: -f1 <<< "$last_line")
+}
+
+get_partition_table() {
+    local dev="$1"
+    if ! output="$("$PARTED" -s -m "$dev" unit s print)"; then
+        log_error "Unable to read partition table for device \`${dev}'"
+    fi
+
     echo "$output"
 }
 
@@ -120,6 +144,13 @@ get_partition_count() {
     expr $(echo "$ptable" | wc -l) - 2
 }
 
+get_partition_by_id() {
+    local ptable="$1"
+    local id="$2"
+
+    grep "^$id:" <<< "$ptable"
+}
+
 get_last_partition() {
     local ptable="$1"
 
@@ -179,32 +210,36 @@ get_last_primary_partition() {
 }
 
 create_partition() {
-    local device=$1
-    local part=$2
-    local ptype=$3
+    local device="$1"
+    local part="$2"
+    local ptype="$3"
 
     declare -a fields
     IFS=":;" read -ra fields <<< "$part"
-    local id=${fields[0]}
-    local start=${fields[1]}
-    local end=${fields[2]}
-    local size=${fields[3]}
-    local fs=${fields[4]}
-    local name=${fields[5]}
-    local flags=${fields[6]//,/ }
-
-    $PARTED -s -m $device mkpart "$ptype" $fs "$start" "$end"
+    local id="${fields[0]}"
+    local start="${fields[1]}"
+    local end="${fields[2]}"
+    local size="${fields[3]}"
+    local fs="${fields[4]}"
+    local name="${fields[5]}"
+    local flags="${fields[6]//,/ }"
+
+    $PARTED -s -m -- $device mkpart "$ptype" $fs "$start" "$end"
     for flag in $flags; do
         $PARTED -s -m $device set "$id" "$flag" on
     done
 }
 
 enlarge_partition() {
-    local device=$1
-    local part=$2
-    local ptype=$3
+    local device="$1"
+    local part="$2"
+    local ptype="$3"
+    local new_end="$4"
+
+    if [ -z "$new_end" ]; then
+        new_end=$(cut -d: -f 3 <<< "$(get_last_free_sector "$device")")
+    fi
 
-    local new_end=$(get_last_free_sector "$device")
     declare -a fields
     IFS=":;" read -ra fields <<< "$part"
     fields[2]="$new_end"
@@ -236,11 +271,17 @@ enlarge_partition() {
 
 get_last_free_sector() {
     local dev="$1"
-    local last_line="$("$PARTED" -s -m "$dev" print free | tail -1)"
-    local ptype="$(echo "$last_line" | cut -d: -f 5)"
+    local unit="$2"
+
+    if [ -n "$unit" ]; then
+        unit="unit $unit"
+    fi
+
+    local last_line="$("$PARTED" -s -m "$dev" "$unit" print free | tail -1)"
+    local ptype="$(cut -d: -f 5 <<< "$last_line")"
 
     if [ "$ptype" = "free;" ]; then
-        echo "$last_line" | cut -d: -f 3
+        echo "$last_line"
     fi
 }
 
@@ -256,11 +297,11 @@ cleanup() {
             # before we give up with an error. This is needed for kpartx when
             # dealing with ntfs partitions mounted through fuse. umount is not
             # synchronous and may return while the partition is still busy. A
-            # premature attempt to delete partition mappings through kpartx on a
-            # device that hosts previously mounted ntfs partition may fail with
-            # a `device-mapper: remove ioctl failed: Device or resource busy'
-            # error. A sensible workaround for this is to wait for a while and
-            # then try again.
+            # premature attempt to delete partition mappings through kpartx on
+            # a device that hosts previously mounted ntfs partition may fail
+            # with a `device-mapper: remove ioctl failed: Device or resource
+            # busy' error. A sensible workaround for this is to wait for a
+            # while and then try again.
             local cmd=${CLEANUP[$i]}
             $cmd || for interval in 0.25 0.5 1 2 4; do
             echo "Command $cmd failed!"
@@ -289,4 +330,5 @@ check_if_excluded() {
 
 trap cleanup EXIT
 set -o pipefail
+
 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
index 623e93b..b60703d 100644 (file)
@@ -59,6 +59,7 @@ target=$(mktemp -d --tmpdir target.XXXXXX)
 add_cleanup rmdir "$target"
 
 export SNF_IMAGE_TARGET="$target"
+export SNF_IMAGE_RESIZE_PART="$(get_last_partition_id "$SNF_IMAGE_DEV")"
 
 if [ ! -d "@tasksdir@" ]; then
     log_error "snf-image/tasks directory is missing"
index 1453b40..034a559 100644 (file)
@@ -43,12 +43,47 @@ table_type=$(get_partition_table_type "$table")
 
 if [ "$table_type" != "msdos" ]; then # We are planning to add gpt support
     log_error "Device: \'${SNF_IMAGE_DEV}' contains unsupported partition "
-        "table type: \`$table_type'. For now only msdos partitions are supported."
+    "table type: \`$table_type'. For now only msdos partitions are supported."
 fi
 
 last_part=$(get_last_partition "$table")
 last_part_id=$(cut -d':' -f1 <<< "$last_part")
 
+# Check if swap is defined...
+if [ -n "$SNF_IMAGE_PROPERTY_SWAP" ]; then
+    if [[ "$SNF_IMAGE_PROPERTY_SWAP" =~ ^([0-9]+):([0-9]+)$ ]]; then
+        swap_num=${BASH_REMATCH[1]}
+        swap_size=${BASH_REMATCH[2]}
+        swap_unit="MB"
+    else
+        log_error "SWAP property \`$SNF_IMAGE_PROPERTY_SWAP' is not valid"
+    fi
+fi
+
+if [ -z "$swap_num" ]; then
+    swap_num=0
+fi
+
+# Most partition setups leave 2048s in the end. For GPT partitions you need at
+# least 34s for the secondary GPT header.
+new_end="-2049"
+
+if [ $swap_num -ne 0 ]; then
+    free=$(get_last_free_sector "$SNF_IMAGE_DEV" "$swap_unit")
+    free_size=$(cut -d: -f4 <<< "$free")
+    free_size_val=${free_size/$swap_unit/}
+    if [ $free_size_val -le $swap_size ]; then
+        log_error "Not enough space for swap partition"
+    fi
+
+    swap_end="$new_end"
+
+    swap_start=$((new_end - (swap_size * 2048) + 1)) # in sectors
+    new_end=$((swap_start - 1))
+fi
+
+extended=""
+
 if [ "$table_type" != "msdos" ]; then
     # Primary, extended and logical partitions is a concept for msdos partition
     # tables. Parted's mkpart will use part-type as partition name if applied
@@ -63,21 +98,52 @@ elif [ $last_part_id -gt 4 ]; then
     last_prim_id=$(cut -d':' -f1 <<< "$last_primary")
 
     if [ "$ext_id" != "$last_prim_id" ]; then
-        #Mark last primary as the last partition
+        # Mark last primary as the last partition
         last_part="$extended"
         last_part_id="$ext_id"
         last_part_type="primary"
     else
-        #enlarge the extended partition
-        enlarge_partition "$SNF_IMAGE_DEV" "$extended" "extended"
+        # Enlarge the extended partition
+        if [ $swap_num -ge 5 ]; then
+            enlarge_partition "$SNF_IMAGE_DEV" "$extended" "extended" "${swap_end}s"
+        else
+            enlarge_partition "$SNF_IMAGE_DEV" "$extended" "extended" "${new_end}s"
+        fi
     fi
 elif [ $(is_extended_partition "$SNF_IMAGE_DEV" "$last_part_id") = "yes" ]; then
     last_part_type="extended"
+    extended="$last_part"
+    if [ $swap_num -ge 5]; then
+        new_end=$swap_end
+    fi
 else
     last_part_type="primary"
+    if [ $swap_num -ge 5 ]; then
+        # This is needed because the swap partition should be added inside a
+        # new extended partition. In order to align the swap partition, we
+        # need to create some extra space between the (aligned) primary and
+        # the swap.
+        new_end=$((new_end - 2048))
+    fi
 fi
 
-enlarge_partition "$SNF_IMAGE_DEV" "$last_part" "$last_part_type"
+enlarge_partition "$SNF_IMAGE_DEV" "$last_part" "$last_part_type" "${new_end}s"
+
+if [ $swap_num -gt 0 ]; then
+    swap_part="$swap_num:${swap_start}s:${swap_end}s:0:linux-swap(v1)::;"
+    if [ "$table_type" != "msdos" ]; then
+        swap_ptype=""
+    elif [ $swap_num -ge 5 ]; then
+        if [ -z "$extended" ]; then
+            extended="0:$((swap_start - 2))s:${swap_end}s:0:::;"
+            create_partition "$SNF_IMAGE_DEV" "$extended" "extended"
+        fi
+        swap_ptype="logical"
+    else
+        swap_ptype="primary"
+    fi
+    create_partition "$SNF_IMAGE_DEV" "$swap_part" "$swap_ptype"
+fi
 
 # Inform the kernel about the changes
 partprobe "$SNF_IMAGE_DEV"
index d3567b0..a12f08d 100644 (file)
@@ -34,10 +34,15 @@ if [ ! -b "$SNF_IMAGE_DEV" ]; then
     log_error "Device file:\`${SNF_IMAGE_DEV}' is not a block device"
 fi
 
+if [ -z "$SNF_IMAGE_RESIZE_PART" ]; then
+    warn "No partition chosen for resize"
+    exit 0
+fi
+
 table=$(get_partition_table "$SNF_IMAGE_DEV")
-last_partition=$(get_last_partition "$table")
-id=$(echo "$last_partition" | cut -d: -f1)
-ptype=$(echo "$last_partition" | cut -d: -f5)
+partition=$(get_partition_by_id "$table" "$SNF_IMAGE_RESIZE_PART")
+id=$(cut -d: -f1 <<< "$partition")
+ptype=$(cut -d: -f5 <<< "$partition")
 
 if [[ "$ptype" == ext[234] ]]; then
     device="${SNF_IMAGE_DEV}${id}"
@@ -57,8 +62,7 @@ if [[ "$ptype" == ext[234] ]]; then
     fi
 
 else
-    warn "Last partition with id: \`$id' has an unsupported file system type:" \
-    " (ptype = $ptype)."
+    warn "Don't know how to resize partition \`$id' with file system \`$ptype'."
 fi
 
 exit 0
index 58a5306..393cb02 100644 (file)
@@ -39,9 +39,9 @@ if [ "$SNF_IMAGE_PROPERTY_OSFAMILY" != "windows" ]; then
 fi
 
 table=$(get_partition_table "$SNF_IMAGE_DEV")
-last_partition=$(get_last_partition "$table")
-id=$(echo "$last_partition" | cut -d: -f1)
-ptype=$(echo "$last_partition" | cut -d: -f5)
+partition=$(get_partition_by_id "$table" "$SNF_IMAGE_RESIZE_PART")
+id=$(cut -d: -f1 <<< "$partition")
+ptype=$(cut -d: -f5 <<< "$partition")
 
 if [ "$ptype" = "ntfs" ]; then
     # Write a diskpart script to %SystemDrive%\Windows\SnfScripts. Sysprep will