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"
}
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"
}
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"
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
}
# 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!"
trap cleanup EXIT
set -o pipefail
+
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
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"
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
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"
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}"
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
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