Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 37 additions & 29 deletions install
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Downloads and installs rpi-clone and rpi-clone-setup into /usr/local/sbin
#
# Command to use to install rpi-clone:
# curl https://raw.githubusercontent.com/geerlingguy/rpi-clone/master/install | sudo bash
# curl https://raw.githubusercontent.com/geerlingguy/rpi-clone/master/install | sudo bash
#
# rpi-clone is Copyright (c) 2018-2019 Bill Wilson
#
Expand All @@ -17,54 +17,62 @@
# This updated code is located in a fork of Bill Willsons git repository
# at https://github.com/geerlingguy/rpi-clone

# shellcheck enable=require-variable-braces

set -uo pipefail

readonly PACKAGE="rpi-clone"
readonly DOWNLOAD_REPOSITORY="https://raw.githubusercontent.com/geerlingguy/rpi-clone/master"
readonly FILES_2_DOWNLOAD"=rpi-clone rpi-clone-setup"
readonly TMP_DIR=$(mktemp -d)
readonly GITHUB_USER="geerlingguy"
readonly DOWNLOAD_REPOSITORY="https://raw.githubusercontent.com/${GITHUB_USER}/${PACKAGE}/master"
readonly FILES_TO_DOWNLOAD=("rpi-clone" "rpi-clone-setup")
readonly DEFAULT_INSTALLATION_DIR="/usr/local/sbin"

pwd=$PWD
trap "{ cd $pwd; rmdir $TMP_DIR &>/dev/null; }" SIGINT SIGTERM EXIT
cd $TMP_DIR
TMP_DIR=$(mktemp -d)
OLD_PWD=${PWD}

trap 'cd "${OLD_PWD}"; rmdir "${TMP_DIR}" &>/dev/null' SIGINT SIGTERM EXIT

cd "${TMP_DIR}" || exit 1

installDir="${1:-$DEFAULT_INSTALLATION_DIR}"
installDir="${1:-${DEFAULT_INSTALLATION_DIR}}"

if [[ ! -d $installDir ]]; then
echo "Installation directory $installDir not found"
if [[ ! -d "${installDir}" ]]; then
echo "Installation directory ${installDir} not found"
echo "Pass a valid installation directory as a parameter to $0"
exit 1
fi

echo "Installing $PACKAGE into $installDir ..."
echo "Installing ${PACKAGE} into ${installDir}..."

for file in $FILES_2_DOWNLOAD; do
echo -n "Downloading $file from $DOWNLOAD_REPOSITORY/$file ... "
http_code=$(curl -w "%{http_code}" -L -s $DOWNLOAD_REPOSITORY/$file -o $file)
(($?)) && {
for file in "${FILES_TO_DOWNLOAD[@]}"; do
echo -n "Downloading ${file} from ${DOWNLOAD_REPOSITORY}/${file}..."

if ! http_code=$(curl -w "%{http_code}" -L -s "${DOWNLOAD_REPOSITORY}/${file}" -o "${file}"); then
echo "Curl failed"
exit 1
}
[[ $http_code != 200 ]] && {
echo "http request failed with $http_code"
fi

if [[ "${http_code}" != 200 ]]; then
echo "http request failed with ${http_code}"
exit 1
}
fi

echo "done"
echo -n "Installing $file into $installDir ... "
sudo chmod +x $file
(($?)) && {

echo -n "Installing ${file} into ${installDir}..."

if ! sudo chmod +x "${file}"; then
echo "chmod failed"
exit 1
}
sudo mv $file $installDir
(($?)) && {
fi

if ! sudo mv "${file}" "${installDir}"; then
echo "mv failed"
exit 1
}
echo "done"
fi

echo "done"
done

echo "$PACKAGE installed"
cd $pwd
echo "${PACKAGE} installed"
cd "${OLD_PWD}" || exit 1
162 changes: 82 additions & 80 deletions rpi-clone
Original file line number Diff line number Diff line change
Expand Up @@ -157,41 +157,39 @@ usage: $PGM sdN {-v|--verbose} {-f|--force-initialize} {-f2}
exit 1
}

readable_MiB() {
readable_size() {
val=$1
if [ "$val" == "" ]; then
result=" ??"
else
blk_size=$2
val=$((val / 1024 * blk_size))
blk_size=$2
format=${4:-MiB} # Default to MiB if not specified

if ((val < 1024 * 1024)); then
result=$(echo $val | awk '{ byte = $1 / 1024; printf "%.1f%s", byte, "M" }')
elif ((val < 1024 * 1024 * 1024)); then
result=$(echo $val | awk '{ byte = $1 / 1024 / 1024; printf "%.1f%s", byte, "G" }')
else
result=$(echo $val | awk '{ byte = $1 / 1024 / 1024 / 1024; printf "%.1f%s", byte, "T" }')
fi
fi
printf -v "${3}" "%s" "$result"
}

readable_MB() {
val=$1
if [ "$val" == "" ]; then
result=" ??"
else
blk_size=$2
val=$((val / 1000 * blk_size))

if ((val < 1000 * 1000)); then
result=$(echo $val | awk '{ byte = $1 / 1000; printf "%.1f%s", byte, "MB" }')
elif ((val < 1000 * 1000 * 1000)); then
result=$(echo $val | awk '{ byte = $1 / 1000 / 1000; printf "%.1f%s", byte, "GB" }')
if [ "$format" == "MB" ]; then
# Decimal (MB, GB, TB)
val=$((val / 1000 * blk_size))

if ((val < 1000 * 1000)); then
result=$(echo $val | awk '{ byte = $1 / 1000; printf "%.1f%s", byte, "MB" }')
elif ((val < 1000 * 1000 * 1000)); then
result=$(echo $val | awk '{ byte = $1 / 1000 / 1000; printf "%.1f%s", byte, "GB" }')
else
result=$(echo $val | awk '{ byte = $1 / 1000 / 1000 / 1000; printf "%.1f%s", byte, "TB" }')
fi
else
result=$(echo $val | awk '{ byte = $1 / 1000 / 1000 / 1000; printf "%.1f%s", byte, "TB" }')
# Binary (MiB, GiB, TiB)
val=$((val / 1024 * blk_size))

if ((val < 1024 * 1024)); then
result=$(echo $val | awk '{ byte = $1 / 1024; printf "%.1f%s", byte, "M" }')
elif ((val < 1024 * 1024 * 1024)); then
result=$(echo $val | awk '{ byte = $1 / 1024 / 1024; printf "%.1f%s", byte, "G" }')
else
result=$(echo $val | awk '{ byte = $1 / 1024 / 1024 / 1024; printf "%.1f%s", byte, "T" }')
fi
fi
fi

printf -v "${3}" "%s" "$result"
}

Expand Down Expand Up @@ -299,8 +297,8 @@ print_partitions() {

n_parts=$(((n_src_parts >= n_dst_parts) ? n_src_parts : n_dst_parts))

readable_MB $src_disk_size "512" src_size_readable
readable_MB $dst_disk_size "512" dst_size_readable
readable_size $src_disk_size "512" src_size_readable "MB"
readable_size $dst_disk_size "512" dst_size_readable "MB"

printf "\n%-43s%s" "Booted disk: $src_disk $src_size_readable" \
"Destination disk: $dst_disk $dst_size_readable"
Expand All @@ -309,7 +307,7 @@ print_partitions() {
out=$'Part, Size,FS,Label ,Part, Size,FS,Label\n'
for ((p = 1; p <= n_parts; p++)); do
if ((p <= n_src_parts && src_exists[p])); then
readable_MiB ${src_size_sectors[p]} "512" tmp
readable_size ${src_size_sectors[p]} "512" tmp
printf -v sectors_readable "%7s" $tmp
pname="$p ${src_name[p]}"
out=${out}$"$pname,$sectors_readable,${src_fs_type[p]},${src_label[p]},"
Expand All @@ -318,7 +316,7 @@ print_partitions() {
fi

if ((p <= n_dst_parts && dst_exists[p])); then
readable_MiB ${dst_size_sectors[p]} "512" tmp
readable_size ${dst_size_sectors[p]} "512" tmp
printf -v sectors_readable "%7s" $tmp
out=${out}$"$p,$sectors_readable,${dst_fs_type[p]},${dst_label[p]},"
else
Expand Down Expand Up @@ -361,8 +359,8 @@ print_sync_actions() {
src_label="/dev/${src_partition[p]}"
action_label="MOUNT SYNC"
fi
readable_MiB ${src_used_sectors[p]} "512" used
readable_MiB ${dst_size_sectors[p]} "512" size
readable_size ${src_used_sectors[p]} "512" used
readable_size ${dst_size_sectors[p]} "512" size
printf "%-22s%-14s : %s %s\n" \
"$src_label" "(${used} used)" "$action_label" \
"$flow (${size} size)"
Expand Down Expand Up @@ -410,10 +408,10 @@ print_image_actions() {
fi

if ((p == n_image_parts)); then
readable_MiB ${src_used_sectors[n_image_parts]} "512" used
readable_size ${src_used_sectors[n_image_parts]} "512" used
printf "%-22s%-14s : RESIZE %s\n" "$pname" "(${used} used)" "$action"
elif ((src_used_sectors[$p] > 0 && p < n_image_parts)); then
readable_MiB ${src_used_sectors[p]} "512" used
readable_size ${src_used_sectors[p]} "512" used
printf "%-22s%-14s : $action\n" "$pname" "(${used} used)"
elif [ "$action" != "" ]; then
printf "%-36s : $action\n" "$pname"
Expand Down Expand Up @@ -561,6 +559,45 @@ get_src_disk() {
printf -v "${3}" "%s" "$num"
}

change_disk_id() {
local disk=$1
local msg=${2:-}

if [ -n "$msg" ]; then
qecho "$msg"
fi

new_id=$(od -A n -t x -N 4 /dev/urandom | tr -d " ")
qprintf "x\ni\n0x$new_id\nr\nw\nq\n" | fdisk /dev/"$disk" > /dev/null

sync
sleep 2
}

find_extended_partition() {
local -r fdisk_table=$1
local -r dev=$(grep "Extended" <<< "${fdisk_table}" | awk '{print $1}')

if [ -n "${dev}" ]; then
echo "${dev: -1}"
else
echo "0"
fi
}

edit_disk_reference() {
local file=$1
local description=$2

if grep -q "$src_disk_ID" "$file"; then
qecho "Editing $description PARTUUID to use $dst_disk_ID"
sed -i "s/${src_disk_ID}/${dst_disk_ID}/g" "$file"
elif [ "$edit_fstab_name" != "" ] && grep -q "${src_part_base}" "$file"; then
qecho "Editing $description references from $src_part_base to $edit_fstab_name"
sed -i "s/${src_part_base}/${edit_fstab_name}/" "$file"
fi
}

# ==== source (booted) disk info and default mount list
#
src_boot_dev=$(findmnt /boot -o source -n | grep "/dev/")
Expand Down Expand Up @@ -634,13 +671,7 @@ Don't know how to partition the destination disk!
exit 1
fi

line=$(echo "$src_fdisk_table" | grep "Extended")
if [ "$line" != "" ]; then
dev=$(echo "$line" | cut -d " " -f 1)
ext_part_num="${dev: -1}"
else
ext_part_num=0
fi
ext_part_num=$(find_extended_partition "$src_fdisk_table")

for ((p = 1; p <= n_src_parts; p++)); do
line=$(echo "$src_partition_table" | grep -e "^${p}:")
Expand Down Expand Up @@ -1028,13 +1059,7 @@ dst_root_dev=/dev/${dst_part_base}${root_part_num}
dst_mount_table=$(findmnt -o source,target -n -l | grep "^/dev/$dst_disk" | tr -s " ")

dst_fdisk_table=$(fdisk -l /dev/$dst_disk | grep "^/dev/")
line=$(echo "$dst_fdisk_table" | grep "Extended")
if [ "$line" != "" ]; then
dev=$(echo "$line" | cut -d " " -f 1)
ext_num="${dev: -1}"
else
ext_num=0
fi
ext_num=$(find_extended_partition "$dst_fdisk_table")

for ((p = 1; p <= n_dst_parts; p++)); do
line=$(echo "$dst_partition_table" | grep -e "^${p}:")
Expand Down Expand Up @@ -1203,7 +1228,7 @@ Use -U for unattended even if initializing.
printf "%-22s : %s\n" "** FATAL **" "Initialize needed - $reason"
printf "%-22s : %s %s %s\n" "" \
"But destination is too small to clone" "$n_image_parts" "partitions."
readable_MiB $((start_sector + 7812)) "512" min_size
readable_size $((start_sector + 7812)) "512" min_size
printf "%-22s : %s\n" "" "Minimum destination size required is $min_size."
if ((n_image_parts > 2)); then
printf "%-22s : %s\n" " " "Possible options:"
Expand All @@ -1222,7 +1247,7 @@ Use -U for unattended even if initializing.
exit 1
fi

readable_MiB $((last_part_sectors + 7812)) "512" image_space_readable
readable_size $((last_part_sectors + 7812)) "512" image_space_readable

echo "== Initialize: IMAGE partition table - $reason =="
print_image_actions
Expand All @@ -1239,7 +1264,7 @@ Use -U for unattended even if initializing.

abort=0
if ((!last_part_space)); then
readable_MiB $last_part_used "512" used_readable
readable_size $last_part_used "512" used_readable
printf "%-22s : %s\n" "** WARNING **" \
"Destination last partition resize to $image_space_readable"
printf "%-22s : %s\n" "" " is too small to hold source used $used_readable."
Expand Down Expand Up @@ -1320,20 +1345,13 @@ Use -U for unattended even if initializing.
printf " Try running $PGM again.\n\n"

# Don't let dst disk keep source disk ID. Can lead to remounts.
new_id=$(od -A n -t x -N 4 /dev/urandom | tr -d " ")
qprintf "x\ni\n0x$new_id\nr\nw\nq\n" | fdisk /dev/$dst_disk > /dev/null
change_disk_id "$dst_disk"
exit 1
fi
done
printf "\n Resize success.\n"
printf " Changing destination Disk ID ..."
sync
sleep 2

new_id=$(od -A n -t x -N 4 /dev/urandom | tr -d " ")
qprintf "x\ni\n0x$new_id\nr\nw\nq\n" | fdisk /dev/$dst_disk > /dev/null
sync
sleep 2
change_disk_id "$dst_disk"
partprobe "/dev/$dst_disk"
sleep 2
echo ""
Expand Down Expand Up @@ -1457,11 +1475,7 @@ fi
line=$(fdisk -l /dev/$dst_disk | grep "Disk identifier:")
dst_disk_ID=${line#*x}
if [ "$dst_disk_ID" == "$src_disk_ID" ]; then
qecho "Destination disk has same Disk ID as source, changing it."
new_id=$(od -A n -t x -N 4 /dev/urandom | tr -d " ")
qprintf "x\ni\n0x$new_id\nr\nw\nq\n" | fdisk /dev/$dst_disk | grep changed
sync
sleep 2
change_disk_id "$dst_disk" "Destination disk has same Disk ID as source, changing it."
partprobe "/dev/$dst_disk"
sleep 2

Expand Down Expand Up @@ -1538,27 +1552,15 @@ if [ -f $cmdline_txt ]; then
cp $cmdline_txt ${clone}/${cmdlinedir}/cmdline.boot
cmdline_txt=${clone}/${cmdlinedir}/cmdline.boot
fi
if grep -q $src_disk_ID $cmdline_txt; then
qecho "Editing $cmdline_txt PARTUUID to use $dst_disk_ID"
sed -i "s/${src_disk_ID}/${dst_disk_ID}/" "$cmdline_txt"
elif [ "$edit_fstab_name" != "" ] && grep -q ${src_part_base} $cmdline_txt; then
qecho "Editing $cmdline_txt references from $src_part_base to $edit_fstab_name"
sed -i "s/${src_part_base}/$edit_fstab_name/" "$cmdline_txt"
fi
edit_disk_reference "$cmdline_txt" "$cmdline_txt"
if ((leave_sd_usb_boot && SD_slot_boot)); then
qecho "Copying USB cmdline.txt to SD card to set up USB boot."
cp /${cmdlinedir}/cmdline.txt /${cmdlinedir}/cmdline.boot
cp $cmdline_txt /${cmdlinedir}/cmdline.txt
fi
fi

if grep -q $src_disk_ID $fstab; then
qecho "Editing $fstab PARTUUID to use $dst_disk_ID"
sed -i "s/${src_disk_ID}/${dst_disk_ID}/g" "$fstab"
elif [ "$edit_fstab_name" != "" ] && grep -q ${src_part_base} $fstab; then
qecho "Editing $fstab references from $src_part_base to $edit_fstab_name"
sed -i "s/${src_part_base}/${edit_fstab_name}/" "$fstab"
fi
edit_disk_reference "$fstab" "$fstab"

rm -f $clone/etc/udev/rules.d/70-persistent-net.rules

Expand Down
Loading