Skip to content

Instantly share code, notes, and snippets.

@smoser
Created December 11, 2013 19:34
Show Gist options
  • Save smoser/7916902 to your computer and use it in GitHub Desktop.
Save smoser/7916902 to your computer and use it in GitHub Desktop.
partition: partition a disk with a single partition using either GPT or MBR partition table format. This is just a simple front end to 'sfdisk' or 'gpt' to put a partition on a image.
#!/bin/bash
VERBOSITY=0
error() { echo "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] target-dev
partition target-dev with a single partition
destroy any partition table that might be there already.
options:
-f | --format F use partition table format F. [mbr, gpt]
default gpt
-E | --end E end the partition at E (unit 1k bytes)
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
debug() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
error "${@}"
}
human2bytes() {
# converts size suitable for input to resize2fs to bytes
# s:512 byte sectors, K:kilobytes, M:megabytes, G:gigabytes
# none: block size of the image
local input=${1} defunit=${2:-1024}
local unit count;
case "$input" in
*s) count=${input%s}; unit=512;;
*K) count=${input%K}; unit=1024;;
*M) count=${input%M}; unit=$((1024*1024));;
*G) count=${input%G}; unit=$((1024*1024*1024));;
*) count=${input} ; unit=${defunit};;
esac
_RET=$((${count}*${unit}))
}
getsize() {
local target="$1"
if [ -b "$target" ]; then
_RET=$(blockdev --getsize64 "$target")
elif [ -f "$target" ]; then
_RET=$(stat "--format=%s" "$target")
else
return 1;
fi
}
wipedev() {
# wipe the front and end (gpt is at end also)
local target="$1" size=""
getsize "$target" ||
{ error "failed to get size of $target"; return 1; }
size="$_RET"
dd if=/dev/zero conv=notrunc of="$target" \
bs=$((1024*1024)) count=1 >/dev/null 2>&1 ||
{ error "failed to zero beginning of $target"; return 1; }
out=$(dd if=/dev/zero conv=notrunc of="$target" bs=1024 \
seek=$(((size/1024)-1024)) count=1024 2>&1)
[ $? -eq 0 ] ||
{ error "failed to wipe end of $target [$size]: $out"; return 1; }
if [ -b "$target" ]; then
blockdev --rereadpt "$target"
udevadm settle
fi
}
pt_gpt() {
local target="$1" end=${2:-""} size="" s512="" ptype="L"
local start="2048" pt1size="" maxend="" out=""
getsize "$target" ||
{ error "failed to get size of $target"; return 1; }
size="$_RET"
if [ -z "$end" ]; then
end=$(($size/512))
else
end=$(($end/512))
fi
maxend=$((($size/512)-2048))
[ "$end" -gt "$maxend" ] && end="$maxend"
debug 1 "maxend=$maxend end=$end size=$size"
out=$(sgdisk --new "1:2048:$end" --typecode=1:8300 "$target") || {
error "$out" 1>&2;
error "failed sgdisk --new \"1:2048:$end\" " \
"--typecode=1:8300 \"$target\""
return 1
}
return 0
}
pt_mbr() {
local target="$1" end=${2:-""} size="" s512="" ptype="L"
local start="2048" pt1size="" maxsize="4294967296"
local isblk=false
getsize "$target" ||
{ error "failed to get size of $target"; return 1; }
size="$_RET"
if [ "$(($size/512))" -gt "$maxsize" ]; then
debug 1 "disk is larger than max for mbr (2TB)"
s512=$maxsize
else
s512=$(($size/512))
fi
if [ -n "$end" ]; then
pt1size=$(((end/512)-2048))
else
pt1size=$((s512-2048))
fi
[ -b "$target" ] && isblk=true
# interact with sfdisk in units of 512 bytes (--unit S)
# we start all partitions at 2048 of those (1M)
local sfdisk_out="" sfdisk_in="2048,$pt1size,$ptype,*" sfdisk_cmd=""
sfdisk_cmd=( sfdisk --no-reread --force --Linux --unit S "$target" )
debug 1 "sfdisking with: echo '$sfdisk_in' | ${sfdisk_cmd[*]}"
sfdisk_out=$(echo "$sfdisk_in" | "${sfdisk_cmd[@]}" 2>&1)
ret=$?
[ $ret -eq 0 ] || {
error "failed to partition $target [${sfdisk_out}]";
return 1;
}
if $isblk; then
blockdev --rereadpt "$target"
udevadm settle
[ -b "${target}1" ] ||
{ error "no partition found ${target}1"; return 1; }
fi
out=$(wipefs "--offset=$(($start*512))" "$target" 2>&1) || {
error "$out";
error "failed to wipefs first partition of $target";
return 1;
}
}
main() {
local short_opts="hE:f:v"
local long_opts="help,end:,format:,verbose"
local getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return; }
local cur="" next=""
local format="gpt" target="" end=""
while [ $# -ne 0 ]; do
cur="$1"; next="$2";
case "$cur" in
-h|--help) Usage ; exit 0;;
-f|--format) format=$next; shift;;
-E|--end) end=$next; shift;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
--) shift; break;;
esac
shift;
done
[ $# -gt 1 ] && { bad_Usage "got $# args, expected 1"; return 1; }
[ $# -eq 0 ] && { bad_Usage "must provide target-dev"; return 1; }
target="$1"
if [ -n "$end" ]; then
human2bytes "$end" ||
{ error "failed to convert '$end' to bytes"; return 1; }
end="$_RET"
fi
[ "$format" = "gpt" -o "$format" = "mbr" ] ||
{ bad_usage "invalid format: $format"; return 1; }
[ -e "$target" ] || { error "$target does not exist"; return 1; }
[ -f "$target" -o -b "$target" ] ||
{ error "$target not a block device"; return 1; }
wipedev "$target" ||
{ error "wiping $target failed"; return 1; }
if [ "$format" = "mbr" ]; then
pt_mbr "$target" "$end"
elif [ "$format" = "gpt" ]; then
pt_gpt "$target" "$end"
fi
return 0
}
main "$@"
# vi: ts=4 noexpandtab
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment