First commit.

This commit is contained in:
2023-03-15 11:18:37 +01:00
commit 5992d41d52
18 changed files with 2036 additions and 0 deletions

View File

@ -0,0 +1,230 @@
#!/bin/bash
trap '{ stty sane; echo ""; errexit "Aborted"; }' SIGINT SIGTERM
MNTPATH="/tmp/boot-gpt-mnt"
mntpart()
{
MNTED=TRUE
if [ ! -d "${MNTPATH}/" ]; then
mkdir "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to make partition mount point"
fi
fi
mount "$1" "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to mount $2 partition"
fi
}
umntpart()
{
umount "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to unmount partition"
fi
rm -r "${MNTPATH}/"
MNTED=FALSE
}
errexit()
{
echo ""
echo "$1"
echo ""
if [ "${MNTED}" = "TRUE" ]; then
umount "${MNTPATH}/" &> /dev/null
rm -rf "${MNTPATH}/" &> /dev/null
fi
echo "Usage: $0 /dev/sdX"
echo ""
exit 1
}
MNTED=FALSE
if [ $(id -u) -ne 0 ]; then
errexit "$0 must be run as root user"
fi
PGMNAME="$(basename $0)"
for PID in $(pidof -x -o %PPID "${PGMNAME}"); do
if [ ${PID} -ne $$ ]; then
errexit "${PGMNAME} is already running"
fi
done
gdisk -l /dev/null &> /dev/null
if [ $? -eq 127 ]; then
echo ""
echo "gdisk not installed"
echo ""
echo -n "Ok to install gdisk (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
echo ""
echo "Installing gdisk"
echo ""
apt-get update
apt-get install gdisk
fi
DEVICE="$1"
if [ "${DEVICE}" = "" ]; then
errexit "No device specified"
fi
if [[ ! "${DEVICE}" =~ ^/dev/sd[a-z]$ || ! -b "${DEVICE}" ]]; then
errexit "Invalid DEVICE: ${DEVICE}"
fi
if [ $(mount | grep -c "^${DEVICE}") -ne 0 ]; then
errexit "${DEVICE} is in use (mounted)"
fi
PTTYPE="$(blkid ${DEVICE} | sed -n 's|^.*PTTYPE="\(\S\+\)".*|\1|p')"
PTTYPE="$(tr [a-z] [A-Z] <<< "${PTTYPE}")"
if [ "${PTTYPE}" = "DOS" ]; then
PTTYPE="MBR"
fi
if [[ "${PTTYPE}" != "MBR" && "${PTTYPE}" != "GPT" ]]; then
errexit "Unsupported partition table type"
fi
echo ""
echo "Partition table type is ${PTTYPE}"
if [ "${PTTYPE}" = "MBR" ]; then
echo ""
echo -n "Ok to convert ${DEVICE} to GPT (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
sgdisk -z "${DEVICE}" &> /dev/null
fi
INFO="$(gdisk -l ${DEVICE})"
LAST=$(sed -n 's|^.*last usable sector is \(\S\+\).*|\1|p' <<< "${INFO}")
START=$(sed -n 's|^\s\+2\s\+\(\S\+\).*|\1|p' <<< "${INFO}")
END=$(sed -n 's|^\s\+2\s\+\S\+\s\+\(\S\+\).*|\1|p' <<< "${INFO}")
SHRINK=FALSE
EXPAND=FALSE
SDBOOT=FALSE
if [ $(grep -c "Warning! Secondary partition table overlaps the last partition" <<< "${INFO}") -ne 0 ]; then
echo ""
echo "ROOT partition overlaps the Secondary partition table area"
echo ""
echo -n "Ok to resize ROOT partition (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
SHRINK=TRUE
elif [ ${END} -lt ${LAST} ]; then
echo ""
echo -n "Expand ROOT partition to use all available space (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
EXPAND=TRUE
fi
break
fi
done
fi
if [ -b /dev/mmcblk0 ]; then
echo ""
echo -n "Set SD card to boot ${DEVICE} (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
SDBOOT=TRUE
fi
break
fi
done
fi
if [[ "${PTTYPE}" = "MBR" || "${SHRINK}" = "TRUE" || "${EXPAND}" = "TRUE" || "${SDBOOT}" = "TRUE" ]]; then
echo ""
echo -n "Ok to process ${DEVICE} (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
if [ "${SHRINK}" = "TRUE" ]; then
echo ""
resize2fs -f -M "${DEVICE}2"
fi
if [[ "${SHRINK}" = "TRUE" || "${EXPAND}" = "TRUE" ]]; then
gdisk "${DEVICE}" <<EOF > /dev/null
d
2
n
2
${START}
w
y
EOF
echo ""
resize2fs -f "${DEVICE}2"
fi
gdisk "${DEVICE}" <<EOF > /dev/null
r
h
1
n
0c
n
n
w
y
EOF
PARTUUID_1="$(blkid ${DEVICE}1 | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
PARTUUID_2="$(blkid ${DEVICE}2 | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
mntpart "${DEVICE}1" "BOOT"
sed -i '/^[[:space:]]*#/!s|\(^.*rootwait\).*$|\1|' "${MNTPATH}/cmdline.txt"
sed -i "/^[[:space:]]*#/!s|^\(.*root=\)\S\+\(\s\+.*\)$|\1PARTUUID=${PARTUUID_2}\2|" "${MNTPATH}/cmdline.txt"
umntpart
mntpart "${DEVICE}2" "ROOT"
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/boot\s\+.*\)$|PARTUUID=${PARTUUID_1}\1|" "${MNTPATH}/etc/fstab"
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/\s\+.*\)$|PARTUUID=${PARTUUID_2}\1|" "${MNTPATH}/etc/fstab"
umntpart
if [ "${SDBOOT}" = "TRUE" ]; then
mntpart "/dev/mmcblk0p1" "BOOT"
sed -i "/^[[:space:]]*#/!s|^\(.*root=\)\S\+\(\s\+.*\)$|\1PARTUUID=${PARTUUID_2}\2|" "${MNTPATH}/cmdline.txt"
umntpart
mntpart "${DEVICE}2" "ROOT"
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/boot\s\+.*\)$|/dev/mmcblk0p1\1|" "${MNTPATH}/etc/fstab"
umntpart
fi
if [[ "${SHRINK}" = "FALSE" && "${EXPAND}" = "FALSE" ]]; then
echo ""
fi
else
echo ""
echo "Nothing to do!"
echo ""
fi

View File

@ -0,0 +1,145 @@
#!/bin/bash
trap '{ stty sane; echo ""; errexit "Aborted"; }' SIGINT SIGTERM
MNTPATH="/tmp/sdc-boot-mnt"
mntpart()
{
MNTED=TRUE
if [ ! -d "${MNTPATH}/" ]; then
mkdir "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to make partition mount point"
fi
fi
mount "$1" "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to mount $2 partition"
fi
}
umntpart()
{
umount "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to unmount partition"
fi
rm -r "${MNTPATH}/"
MNTED=FALSE
}
errexit()
{
echo ""
echo "$1"
echo ""
if [ "${MNTED}" = "TRUE" ]; then
umount "${MNTPATH}/" &> /dev/null
rm -rf "${MNTPATH}/" &> /dev/null
fi
echo "Usage: $0 [ /dev/sdX2 | /dev/mmcblk0p2 | hhhhhhhh-02 | hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh ]"
echo ""
exit 1
}
MNTED=FALSE
if [ $(id -u) -ne 0 ]; then
errexit "$0 must be run as root user"
fi
PGMNAME="$(basename $0)"
for PID in $(pidof -x -o %PPID "${PGMNAME}"); do
if [ ${PID} -ne $$ ]; then
errexit "${PGMNAME} is already running"
fi
done
if [ ! -b /dev/mmcblk0 ]; then
errexit "No SD card present"
fi
DEVICE="$1"
if [ "${DEVICE}" = "" ]; then
mntpart "/dev/mmcblk0p1" "SD card BOOT"
DEVICE="$(sed -n '/^[[:space:]]*#/!s|^.*root=\(\S\+\)\s\+.*$|\1|p' "${MNTPATH}/cmdline.txt")"
umntpart
if [[ "${DEVICE}" =~ ^PARTUUID=.*$ ]]; then
DEVICE="$(blkid -l -t "${DEVICE}" | sed -n 's|^\(/dev/.*\):.*|\1|p')"
fi
PARTUUID="$(blkid "${DEVICE}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
else
DEVICE="$(tr [A-Z] [a-z] <<< "${DEVICE}")"
if [[ "${DEVICE}" =~ ^[[:xdigit:]]{8}-02$ || "${DEVICE}" =~ ^[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}$ ]]; then
PARTUUID="${DEVICE}"
BLKID="$(blkid -l -t PARTUUID="${PARTUUID}")"
if [ $? -ne 0 ]; then
errexit "Invalid DEVICE: ${DEVICE}"
fi
DEVICE="$(sed -n 's|^\(/dev/.*\):.*$|\1|p' <<< "${BLKID}")"
fi
if [[ ("${DEVICE}" != "/dev/mmcblk0p2" && ! "${DEVICE}" =~ ^/dev/sd[a-z]2$) || ! -b "${DEVICE}" ]]; then
errexit "Invalid DEVICE: ${DEVICE}"
fi
PARTUUID="$(blkid "${DEVICE}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
echo ""
echo -n "Set SD card to boot to ${DEVICE} [PARTUUID=${PARTUUID}] (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
mntpart "/dev/mmcblk0p1" "SD card BOOT"
if [ "${DEVICE}" = "/dev/mmcblk0p2" ]; then
sed -i "/^[[:space:]]*#/!s|^\(.*root=\)\S\+\(\s\+.*\)$|\1/dev/mmcblk0p2\2|" "${MNTPATH}/cmdline.txt"
else
sed -i "/^[[:space:]]*#/!s|^\(.*root=\)\S\+\(\s\+.*\)$|\1PARTUUID=${PARTUUID}\2|" "${MNTPATH}/cmdline.txt"
fi
umntpart
if [ "${DEVICE}" != "/dev/mmcblk0p2" ]; then
mntpart "${DEVICE}" "device ROOT"
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/boot\s\+.*\)$|/dev/mmcblk0p1\1|" "${MNTPATH}/etc/fstab"
umntpart
fi
fi
echo ""
echo "SD card is set to boot to ${DEVICE} [PARTUUID=${PARTUUID}]"
if [[ "${DEVICE}" != "/dev/mmcblk0p2" && "$(blkid /dev/mmcblk0p2 | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" = "${PARTUUID}" ]]; then
echo ""
echo "WARNING : SD card (/dev/mmcblk0p2) and USB device (${DEVICE}) have the same PARTUUID (${PARTUUID}) : SD card will boot instead of USB device"
fi
DEV_LIST=()
DEV_LIST+=/dev/mmcblk0p2
DEV_LIST+=($(ls -l /dev/sd?2 2> /dev/null | sed -n 's|^.*\(/dev/.*\)|\1|p'))
if [ ${#DEV_LIST[@]} -gt 1 ]; then
for i in ${!DEV_LIST[@]}; do
if [ ${i} -lt $((${#DEV_LIST[@]} - 1)) ]; then
j=$((i + 1))
while [ ${j} -lt ${#DEV_LIST[@]} ]; do
if [ "$(blkid "${DEV_LIST[i]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" = "$(blkid "${DEV_LIST[j]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" ];then
if [[ "${DEV_LIST[i]}" != "/dev/mmcblk0p2" && ("${DEV_LIST[i]}" = "${DEVICE}" || "${DEV_LIST[j]}" = "${DEVICE}") ]]; then
echo ""
echo "WARNING : ${DEV_LIST[i]} and ${DEV_LIST[j]} have the same PARTUUID : $(blkid "${DEV_LIST[i]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
fi
fi
((j += 1))
done
fi
done
fi
echo ""
if [ "$1" != "" ]; then
echo -n "Reboot now (y/n)? "
while read -r -n 1 -s answer; do
if [[ ${answer} = [yYnN] ]]; then
echo "${answer}"
if [[ ${answer} = [yY] ]]; then
shutdown -r now
fi
break
fi
done
echo ""
fi

View File

@ -0,0 +1,193 @@
#!/bin/bash
trap '{ stty sane; echo ""; errexit "Aborted"; }' SIGINT SIGTERM
MNTPATH="/tmp/set-partuuid-mnt"
mntpart()
{
MNTED=TRUE
if [ ! -d "${MNTPATH}/" ]; then
mkdir "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to make partition mount point"
fi
fi
mount "$1" "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to mount $2 partition"
fi
}
umntpart()
{
umount "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to unmount partition"
fi
rm -r "${MNTPATH}/"
MNTED=FALSE
}
errexit()
{
echo ""
echo "$1"
echo ""
if [ "${MNTED}" = "TRUE" ]; then
umount "${MNTPATH}/" &> /dev/null
rm -rf "${MNTPATH}/" &> /dev/null
fi
echo "Usage: $0 device [ hhhhhhhh-02 | hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh | random ]"
echo ""
exit 1
}
MNTED=FALSE
if [ $(id -u) -ne 0 ]; then
errexit "$0 must be run as root user"
fi
PGMNAME="$(basename $0)"
for PID in $(pidof -x -o %PPID "${PGMNAME}"); do
if [ ${PID} -ne $$ ]; then
errexit "${PGMNAME} is already running"
fi
done
gdisk -l "${DEVICE}" &> /dev/null
if [ $? -eq 127 ]; then
echo ""
echo "gdisk not installed"
echo ""
echo -n "Ok to install gdisk (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
echo ""
echo "Installing gdisk"
echo ""
apt-get update
apt-get install gdisk
fi
DEVICE="$1"
PARTUUID="$2"
if [[ (! "${DEVICE}" =~ ^/dev/sd[a-z]2$ && ! "${DEVICE}" = "/dev/mmcblk0p2") || ! -b "${DEVICE}" ]]; then
errexit "Invalid DEVICE: ${DEVICE}"
fi
ORIGUUID="$(blkid "${DEVICE}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
if [ "${PARTUUID}" = "" ]; then
PARTUUID="${ORIGUUID}"
else
DEVICE_P="$(sed 's/[0-9]\+$//' <<< "${DEVICE}")"
DEVICE_D="${DEVICE_P}"
if [ "${DEVICE_D}" = "/dev/mmcblk0p" ]; then
DEVICE_D="${DEVICE_D:0:(${#DEVICE_D} - 1)}"
fi
SDCBOOT=FALSE
if [ -b /dev/mmcblk0p1 ]; then
mntpart "/dev/mmcblk0p1" "BOOT"
CLRPART="$(sed -n '/^[[:space:]]*#/!s|^.*root=\(\S\+\)\s.*|\1|p' "${MNTPATH}/cmdline.txt")"
if [ "${CLRPART}" != "/dev/mmcblk0p2" ]; then
CLRUUID="$(sed -n 's|PARTUUID=\(\S\+\)|\1|p' <<< "${CLRPART}")"
if [[ "${CLRUUID}" != "$(blkid /dev/mmcblk0p2 | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" && "${CLRUUID}" = "${ORIGUUID}" ]]; then
SDCBOOT=TRUE
fi
fi
umntpart
fi
PTTYPE="$(blkid "${DEVICE_D}" | sed -n 's|^.*PTTYPE="\(\S\+\)".*|\1|p')"
if [[ "${PTTYPE}" != "dos" && "${PTTYPE}" != "gpt" ]]; then
errexit "Unsupported partition table type: ${PTTYPE}"
fi
PARTUUID="$(tr [A-Z] [a-z] <<< "${PARTUUID}")"
if [[ "${PARTUUID}" != "random" && (("${PTTYPE}" = "dos" && ! "${PARTUUID}" =~ ^[[:xdigit:]]{8}-02$) || \
("${PTTYPE}" = "gpt" && ! "${PARTUUID}" =~ ^[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}$)) ]]; then
errexit "Invalid PARTUUID: ${PARTUUID}"
fi
echo ""
echo -n "Set PARTUUID on ${DEVICE} to ${PARTUUID} (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
ORIGUUID_1="$(blkid "${DEVICE_P}1" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
ORIGUUID_2="$(blkid "${DEVICE_P}2" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
if [ "${PTTYPE}" = "dos" ]; then
if [ "${PARTUUID}" = "random" ]; then
PTUUID="$(hexdump -n 4 -e '"%08X"' /dev/random | tr [A-Z] [a-z])"
else
PTUUID="${PARTUUID:0:(${#PARTUUID} - 3)}"
fi
fdisk "${DEVICE_D}" <<EOF &> /dev/null
x
i
0x${PTUUID}
r
w
EOF
else
if [ "${PARTUUID}" = "random" ]; then
sgdisk -u 2:'R' "${DEVICE_D}" > /dev/null
else
sgdisk -u 2:${PARTUUID} "${DEVICE_D}" > /dev/null
fi
fi
partprobe
PARTUUID="$(blkid "${DEVICE}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
PARTUUID_1="$(blkid "${DEVICE_P}1" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
PARTUUID_2="$(blkid "${DEVICE_P}2" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
mntpart "${DEVICE_P}2" "ROOT"
sed -i "/^[[:space:]]*#/!s|^\(PARTUUID=\)${ORIGUUID_1}\(\s\+/boot\s\+.*\)$|\1${PARTUUID_1}\2|" "${MNTPATH}/etc/fstab"
sed -i "/^[[:space:]]*#/!s|^\(PARTUUID=\)${ORIGUUID_2}\(\s\+/\s\+.*\)$|\1${PARTUUID_2}\2|" "${MNTPATH}/etc/fstab"
umntpart
mntpart "${DEVICE_P}1" "BOOT"
sed -i "/^[[:space:]]*#/!s|^\(.*root=PARTUUID=\)${ORIGUUID_2}\(\s\+.*\)$|\1${PARTUUID_2}\2|" "${MNTPATH}/cmdline.txt"
umntpart
if [ "${SDCBOOT}" = "TRUE" ]; then
mntpart "/dev/mmcblk0p1" "SD card BOOT"
sed -i "/^[[:space:]]*#/!s|^\(.*root=PARTUUID=\)${ORIGUUID_2}\(\s\+.*\)$|\1${PARTUUID_2}\2|" "${MNTPATH}/cmdline.txt"
umntpart
fi
fi
echo ""
echo "PARTUUID on ${DEVICE} is set to ${PARTUUID}"
if [ -b /dev/mmcblk0 ]; then
if [[ "${DEVICE}" != "/dev/mmcblk0p2" && "$(blkid /dev/mmcblk0p2 | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" = "${PARTUUID}" ]]; then
echo ""
echo "WARNING : SD card (/dev/mmcblk0p2) and USB device (${DEVICE}) have the same PARTUUID (${PARTUUID}) : SD card will boot instead of USB device"
fi
fi
DEV_LIST=()
if [ -b /dev/mmcblk0 ]; then
DEV_LIST+=/dev/mmcblk0p2
fi
DEV_LIST+=($(ls -l /dev/sd?2 2> /dev/null | sed -n 's|^.*\(/dev/.*\)|\1|p'))
if [ ${#DEV_LIST[@]} -gt 1 ]; then
for i in ${!DEV_LIST[@]}; do
if [ ${i} -lt $((${#DEV_LIST[@]} - 1)) ]; then
j=$((i + 1))
while [ ${j} -lt ${#DEV_LIST[@]} ]; do
if [ "$(blkid "${DEV_LIST[i]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" = "$(blkid "${DEV_LIST[j]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" ];then
if [[ "${DEV_LIST[i]}" != "/dev/mmcblk0p2" && ("${DEV_LIST[i]}" = "${DEVICE}" || "${DEV_LIST[j]}" = "${DEVICE}") ]]; then
echo ""
echo "WARNING : ${DEV_LIST[i]} and ${DEV_LIST[j]} have the same PARTUUID : $(blkid "${DEV_LIST[i]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
fi
fi
((j += 1))
done
fi
done
fi
echo ""

View File

@ -0,0 +1,403 @@
#!/bin/bash
trap '{ stty sane; echo ""; errexit "Aborted"; }' SIGINT SIGTERM
MNTPATH="/tmp/usb-boot-mnt"
mntdev()
{
MNTED=TRUE
if [ ! -d "${MNTPATH}/" ]; then
mkdir "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to make ROOT partition mount point"
fi
fi
mount "${1}2" "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to mount ROOT partition"
fi
if [ ! -d "${MNTPATH}/boot/" ]; then
mkdir -p "${MNTPATH}/boot/"
if [ $? -ne 0 ]; then
errexit "Unable to make BOOT partition mount point"
fi
fi
mount "${1}1" "${MNTPATH}/boot/"
if [ $? -ne 0 ]; then
errexit "Unable to mount BOOT partition"
fi
}
umntdev()
{
umount "${MNTPATH}/boot/"
if [ $? -ne 0 ]; then
errexit "Unable to unmount BOOT partition"
fi
umount "${MNTPATH}/"
if [ $? -ne 0 ]; then
errexit "Unable to unmount ROOT partition"
fi
rm -r "${MNTPATH}/"
MNTED=FALSE
}
errexit()
{
echo ""
echo "$1"
echo ""
if [ "${MNTED}" = "TRUE" ]; then
umount "${MNTPATH}/boot/" &> /dev/null
umount "${MNTPATH}/" &> /dev/null
rm -rf "${MNTPATH}/" &> /dev/null
fi
exit 1
}
MNTED=FALSE
if [ $(id -u) -ne 0 ]; then
errexit "Must be run as root user: sudo $0"
fi
PGMNAME="$(basename $0)"
for PID in $(pidof -x -o %PPID "${PGMNAME}"); do
if [ ${PID} -ne $$ ]; then
errexit "${PGMNAME} is already running"
fi
done
gdisk -l "${DEVICE}" &> /dev/null
if [ $? -eq 127 ]; then
echo ""
echo "gdisk not installed"
echo ""
echo -n "Ok to install gdisk (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
errexit "Aborted"
fi
fi
done
echo ""
echo "Installing gdisk"
echo ""
apt-get update
apt-get install gdisk
fi
rsync --version &> /dev/null
if [ $? -ne 0 ]; then
errexit "rsync not installed (run: apt-get install rsync)"
fi
ROOT_PART="$(mount | sed -n 's|^\(/dev/.*\) on / .*|\1|p')"
ROOT_DEV="$(sed 's/[0-9]\+$//' <<< "${ROOT_PART}")"
if [ "${ROOT_DEV}" = "/dev/mmcblk0p" ]; then
ROOT_DEV="${ROOT_DEV:0:(${#ROOT_DEV} - 1)}"
fi
ROOT_TYPE="$(blkid "${ROOT_PART}" | sed -n 's|^.*TYPE="\(\S\+\)".*|\1|p')"
if [ -b /dev/mmcblk0 ]; then
USESDC=TRUE
else
USESDC=FALSE
fi
if [[ $(cat /proc/cpuinfo | grep -c "^Revision\s\+:\s\+[abcd]0311[1245]$") -ne 0 || $(cat /proc/cpuinfo | grep -c "^Revision\s\+:\s\+c03130$") -ne 0 ]]; then
RPI_4=TRUE
else
RPI_4=FALSE
fi
if [ "$(vcgencmd otp_dump | grep 17:)" = "17:3020000a" ]; then
RPI_3=TRUE
else
RPI_3=FALSE
fi
if [[ "${USESDC}" = "TRUE" && "${RPI_4}" = "TRUE" ]]; then
whiptail --backtitle "USB Boot" --title "USB Boot Method" --yesno --defaultno "\nUse SD card to boot the USB device?" 12 40
YESNO=$?
if [ ${YESNO} -eq 255 ]; then
errexit "Aborted"
elif [ ${YESNO} -ne 0 ]; then
USESDC=FALSE
fi
elif [[ "${USESDC}" = "TRUE" && "${RPI_3}" = "TRUE" ]]; then
whiptail --backtitle "USB Boot" --title "USB Boot Method" --yesno "\nUse SD card to boot the USB device (recommended)?" 12 54
YESNO=$?
if [ ${YESNO} -eq 255 ]; then
errexit "Aborted"
elif [ ${YESNO} -ne 0 ]; then
USESDC=FALSE
fi
elif [[ "${USESDC}" = "FALSE" && "${RPI_4}" = "FALSE" && "${RPI_3}" = "FALSE" ]]; then
errexit "Not a Raspberry Pi 4, Raspberry Pi 3B+, or Raspberry Pi 3B with OTP set, and no SD card present or used"
fi
USBDEVS=($(ls -l /dev/sd? 2> /dev/null | sed -n 's|^.*\(/dev/.*\)|\1|p'))
if [ ${#USBDEVS[@]} -eq 0 ]; then
errexit "No available USB mass storage devices found"
fi
for i in ${!USBDEVS[@]}; do
USBDEVS[i]="${USBDEVS[i]} ${USBDEVS[i]} OFF"
done
USB_DEST="$(whiptail --backtitle "USB Boot" --title "USB Mass Storage Devices" --notags --radiolist \
"\nSelect the USB mass storage device to boot" 13 47 ${#USBDEVS[@]} ${USBDEVS[@]} 3>&1 1>&2 2>&3)"
if [[ $? -ne 0 || "${USB_DEST}" = "" ]]; then
errexit "Aborted"
fi
USB_BOOT="${USB_DEST}1"
USB_ROOT="${USB_DEST}2"
if [ "${ROOT_DEV}" != "${USB_DEST}" ]; then
whiptail --backtitle "USB Boot" --title "Replicate BOOT/ROOT Contents" --yesno "\nReplicate BOOT/ROOT contents from ${ROOT_DEV} to ${USB_DEST}?" 12 64
YESNO=$?
if [ ${YESNO} -eq 255 ]; then
errexit "Aborted"
elif [ ${YESNO} -eq 0 ]; then
if [ $(mount | grep -c "^${USB_DEST}") -ne 0 ]; then
errexit "USB mass storage device in use (mounted)"
fi
DEVSIZE=$(blockdev --getsz "${USB_DEST}")
PTTYPES=()
if [ ${DEVSIZE} -le 4294966784 ]; then
PTTYPES[0]="dos MBR ON"
PTTYPES[1]="gpt GPT OFF"
else
PTTYPES[0]="gpt GPT ON"
fi
PTTYPE="$(whiptail --backtitle "USB Boot" --title "Partition Table Type" --notags --radiolist \
"\nSelect the partition table type to use (MBR = 2TB Maximum)" 10 62 ${#PTTYPES[@]} ${PTTYPES[@]} 3>&1 1>&2 2>&3)"
if [[ $? -ne 0 || "${PTTYPE}" = "" ]]; then
errexit "Aborted"
fi
whiptail --backtitle "USB Boot" --title "WARNING" --yesno "\nWARNING\n\nAll existing data on USB device ${USB_DEST} will be destroyed!\n\nDo you wish to continue?" 14 64
YESNO=$?
if [ ${YESNO} -ne 0 ]; then
errexit "Aborted"
fi
echo ""
echo "Replicating BOOT/ROOT contents from ${ROOT_DEV} to ${USB_DEST} (this will take a while)"
if [ "${PTTYPE}" = "dos" ]; then
DEVSIZE=$(blockdev --getsz "${USB_DEST}")
dd bs=512 seek=0 count=34 if=/dev/zero of="${USB_DEST}" &> /dev/null
dd bs=512 seek=$((${DEVSIZE} - 33)) count=33 if=/dev/zero of="${USB_DEST}" &> /dev/null
partprobe
echo "label: dos" | sfdisk "${USB_DEST}" > /dev/null
sfdisk "${USB_DEST}" <<EOF &> /dev/null
,256MiB,c
,+,83
EOF
else
sgdisk -Z "${USB_DEST}" &> /dev/null
sgdisk -n 1:0:+256M "${USB_DEST}" &> /dev/null
sgdisk -t 1:0700 "${USB_DEST}" > /dev/null
sgdisk -n 2:0:0 "${USB_DEST}" &> /dev/null
sgdisk -t 2:8300 "${USB_DEST}" > /dev/null
fi
partprobe
mkfs.vfat -F 32 "${USB_BOOT}" > /dev/null
if [ $? -ne 0 ]; then
errexit "Unable to create BOOT filesystem"
fi
dosfsck "${USB_BOOT}" > /dev/null
if [ $? -ne 0 ]; then
errexit "BOOT filesystem appears corrupted"
fi
if [ "${ROOT_TYPE}" = "f2fs" ]; then
mkfs.f2fs -f "${USB_ROOT}" > /dev/null
else
mkfs.ext4 -F -q -b 4096 "${USB_ROOT}" > /dev/null
fi
if [ $? -ne 0 ]; then
errexit "Unable to create ROOT filesystem"
fi
mntdev "${USB_DEST}"
rsync -aDH --partial --numeric-ids --delete --force --exclude "${MNTPATH}" --exclude '/dev' --exclude '/lost+found' --exclude '/media' --exclude '/mnt' \
--exclude '/proc' --exclude '/run' --exclude '/sys' --exclude '/tmp' --exclude '/etc/udev/rules.d/70-persistent-net.rules' \
--exclude '/var/lib/asterisk/astdb.sqlite3-journal' "${OPTIONS[@]}" / "${MNTPATH}/"
if [[ $? -ne 0 && $? -ne 24 ]]; then
errexit "Unable to replicate BOOT/ROOT contents from ${ROOT_DEV} to ${USB_DEST}"
fi
mkdir -p "${MNTPATH}/dev/" "${MNTPATH}/lost+found/" "${MNTPATH}/media/" "${MNTPATH}/mnt/" "${MNTPATH}/proc/" "${MNTPATH}/run/" "${MNTPATH}/sys/" "${MNTPATH}/tmp/"
if [ $? -ne 0 ]; then
errexit "Unable to create directories"
fi
chmod a+rwxt "${MNTPATH}/tmp/"
umntdev
echo ""
echo "BOOT/ROOT contents replicated from ${ROOT_DEV} to ${USB_DEST}"
fi
fi
if [ "${USESDC}" = "TRUE" ]; then
if [ -b /dev/mmcblk0 ]; then
while [ "$(blkid /dev/mmcblk0p2 | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" = "$(blkid ${USB_DEST}2 | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" ]
do
echo ""
echo "WARNING : SD card (/dev/mmcblk0) and USB device (${USB_DEST}) have the same PARTUUID : SD card will boot instead of USB device"
echo ""
echo -n "Ok to change PARTUUID on USB device (${USB_DEST}) (y/n)? "
while read -r -n 1 -s answer; do
if [[ "${answer}" = [yYnN] ]]; then
echo "${answer}"
if [[ "${answer}" = [yY] ]]; then
break
else
break 2
fi
fi
done
echo ""
echo "Changing PARTUUID on USB device (${USB_DEST})"
PTTYPE="$(blkid "${USB_DEST}" | sed -n 's|^.*PTTYPE="\(\S\+\)".*|\1|p')"
if [ "${PTTYPE}" = "dos" ]; then
PTUUID="$(hexdump -n 4 -e '"%08X"' /dev/random | tr [A-Z] [a-z])"
fdisk "${USB_DEST}" <<EOF &> /dev/null
x
i
0x${PTUUID}
r
w
EOF
else
sgdisk -u 2:'R' "${USB_DEST}" &> /dev/null
fi
done
else
errexit "No SD card present"
fi
fi
if [ "${PTTYPE}" = "gpt" ]; then
gdisk "${USB_DEST}" <<EOF > /dev/null
r
h
1
n
0c
n
n
w
y
EOF
fi
partprobe &> /dev/null
PARTUUID_1="$(blkid "${USB_BOOT}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
PARTUUID_2="$(blkid "${USB_ROOT}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
if [ "${USESDC}" = "TRUE" ]; then
if [ -b /dev/mmcblk0 ]; then
mntdev "/dev/mmcblk0p"
sed -i "/^[[:space:]]*#/!s|^\(.*root=\)\S\+\(\s\+.*\)$|\1PARTUUID=${PARTUUID_2}\2|" "${MNTPATH}/boot/cmdline.txt"
umntdev
else
errexit "No SD card present"
fi
fi
mntdev "${USB_DEST}"
sed -i "/^[[:space:]]*#/!s|^\(.*root=\)\S\+\(\s\+.*\)$|\1PARTUUID=${PARTUUID_2}\2|" "${MNTPATH}/boot/cmdline.txt"
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/\s\+.*\)$|PARTUUID=${PARTUUID_2}\1|" "${MNTPATH}/etc/fstab"
if [ "${USESDC}" = "TRUE" ]; then
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/boot\s\+.*\)$|/dev/mmcblk0p1\1|" "${MNTPATH}/etc/fstab"
if [ $(grep -v '^[[:space:]]*#' "${MNTPATH}/etc/rc.local" | grep -c 'usb-boot-init') -eq 0 ]; then
cat <<\EOF1 > "${MNTPATH}/etc/usb-boot-init"
#!/bin/bash
MNTBOOT="/tmp/usb-boot-init-mnt"
REBOOT=FALSE
ROOT_PART="$(mount | sed -n 's|^\(/dev/.*\) on / .*|\1|p')"
ROOT_DEV="$(sed 's/[0-9]\+$//' <<< "${ROOT_PART}")"
if [ "${ROOT_DEV}" = "/dev/mmcblk0p" ]; then
ROOT_DEV="${ROOT_DEV:0:(${#ROOT_DEV} - 1)}"
fi
mkdir -p "${MNTBOOT}/"
mount "${ROOT_DEV}1" "${MNTBOOT}/"
if [ "$(find "${MNTBOOT}/" -type f -iregex "${MNTBOOT}/ssh\(\.txt\)?" -print -delete)" != "" ]; then
update-rc.d ssh enable && invoke-rc.d ssh start
fi
if [ -f "${MNTBOOT}/wpa_supplicant.conf" ]; then
mv "${MNTBOOT}/wpa_supplicant.conf" /etc/wpa_supplicant/wpa_supplicant.conf
REBOOT=TRUE
fi
if [[ $(grep -v '^[[:space:]]*#' "${MNTBOOT}/cmdline.txt" | grep -c 'init=/usr/lib/raspi-config/init_resize.sh') -ne 0 ]]; then
sed -i '/^[[:space:]]*#/!s| init=/usr/lib/raspi-config/init_resize\.sh||' "${MNTBOOT}/cmdline.txt"
START2=$(sfdisk -d "${ROOT_DEV}" | sed -n "s|^${ROOT_PART}\s\+:.*start=\s*\([0-9]\+\).*$|\1|p")
PTTYPE="$(blkid "${ROOT_DEV}" | sed -n 's|^.*PTTYPE="\(\S\+\)".*|\1|p')"
if [ "${PTTYPE}" = "dos" ]; then
sfdisk --delete "${ROOT_DEV}" 2 > /dev/null
echo "${START2},+" | sfdisk --no-reread --no-tell-kernel -N2 "${ROOT_DEV}" &> /dev/null
else
PARTUUID="$(blkid "${ROOT_PART}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
sgdisk -d 2 "${ROOT_DEV}" > /dev/null
sgdisk -n 2:${START2}:0 "${ROOT_DEV}" > /dev/null
sgdisk -u 2:${PARTUUID} "${ROOT_DEV}" > /dev/null
fi
cat <<\EOF2 > /etc/init.d/resize_root_fs
#!/bin/sh
### BEGIN INIT INFO
# Provides: resize_root_fs
# Required-Start:
# Required-Stop:
# Default-Start: 3
# Default-Stop:
# Short-Description: Resize root filesystem
# Description:
### END INIT INFO
case "$1" in
start)
resize2fs "$(mount | sed -n 's|^\(/dev/.*\) on / .*|\1|p')"
update-rc.d resize_root_fs remove
rm /etc/init.d/resize_root_fs
;;
*)
exit 3
;;
esac
EOF2
chmod +x /etc/init.d/resize_root_fs
update-rc.d resize_root_fs defaults
REBOOT=TRUE
fi
umount "${MNTBOOT}/"
rm -r "${MNTBOOT}/"
sed -i '/usb-boot-init/d' /etc/rc.local
rm /etc/usb-boot-init
if [ "${REBOOT}" = "TRUE" ]; then
shutdown --no-wall -r now
fi
EOF1
chmod +x "${MNTPATH}/etc/usb-boot-init"
sed -i 's|^exit 0$|/etc/usb-boot-init\nexit 0|' "${MNTPATH}/etc/rc.local"
fi
else
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/boot\s\+.*\)$|PARTUUID=${PARTUUID_1}\1|" "${MNTPATH}/etc/fstab"
fi
umntdev
DEV_LIST=()
if [ -b /dev/mmcblk0 ]; then
DEV_LIST+=/dev/mmcblk0p2
fi
DEV_LIST+=($(ls -l /dev/sd?2 2> /dev/null | sed -n 's|^.*\(/dev/.*\)|\1|p'))
if [ ${#DEV_LIST[@]} -gt 1 ]; then
for i in ${!DEV_LIST[@]}; do
if [ ${i} -lt $((${#DEV_LIST[@]} - 1)) ]; then
j=$((i + 1))
while [ ${j} -lt ${#DEV_LIST[@]} ]; do
if [ "$(blkid "${DEV_LIST[i]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" = "$(blkid "${DEV_LIST[j]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')" ]; then
if [[ "${DEV_LIST[i]}" != "/dev/mmcblk0p2" || "${DEV_LIST[j]}" != "${USB_DEST}2" ]]; then
echo ""
echo "WARNING : ${DEV_LIST[i]} and ${DEV_LIST[j]} have the same PARTUUID : $(blkid "${DEV_LIST[i]}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
fi
fi
((j += 1))
done
fi
done
fi
if [ "${USESDC}" = "TRUE" ]; then
echo ""
echo "SD card must remain in place to boot the USB device"
else
if [ -b /dev/mmcblk0 ]; then
echo ""
echo "SD card must be removed to boot the USB device"
fi
fi
echo ""

View File

@ -0,0 +1,89 @@
Running Raspbian on USB Devices : Made Easy
A recurring topic of discussion is how to configure and reliably run Raspbian on a USB flash drive, USB hard drive, or USB SSD instead of an SD card.
A Raspberry Pi 3B+ has a native USB boot mode (this mode has to be manually enabled by setting an OTP bit on a Raspberry Pi 3B). This native USB boot mode has serious compatibility issues. A bootcode.bin file is available for older Raspberry Pi models. Unfortunately, both of these approaches have serious limitations and once working, can easily be broken by simply plugging in an additional USB storage device.
The easiest and most reliable way to run Raspbian on a USB device with any Raspberry Pi is to leave an SD card containing Raspbian in place, but use it only for starting Raspbian that is residing on a USB device. While setting up such a configuration is not rocket science, it can be confusing to a newcomer or someone unfamiliar with Linux internals. In an effort to simplify the task, I've created the attached script named 'usb-boot' to automate the process.
If usb-boot is running on a Raspberry Pi 4, usb-boot first prompts: 'Use SD card to boot the USB device?'
If 'No' is selected, the SD card will not be altered and the direct USB boot capability of the Raspberry Pi 4 will be used.
[NOTE: The direct USB boot capability of the Raspberry Pi 4 requires an updated bootloader and firmware: https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711_bootloader_config.md]
If usb-boot is running on a Raspberry Pi 3B+ or a Raspberry Pi 3B with its OTP bit set, usb-boot first prompts: 'Use SD card to boot the USB device (recommended)?'
If 'No' is selected, the SD card will not be altered, but booting the USB device may be limited and/or unreliable as described above.
usb-boot then presents a list of available USB mass storage devices and prompts: 'Select the USB mass storage device to boot'
Use the arrow keys on your keyboard to navigate to the desired device and press the spacebar to select it. Then use the tab key to navigate to the 'Ok' or 'Cancel' button and press the return key.
usb-boot will then prompt: 'Replicate BOOT/ROOT contents from /dev/mmcblk0 to /dev/sdX?'
/dev/mmcblk0 is the SD card and /dev/sdX is the USB device.
Select 'No' if the USB device already has Raspbian on it and you wish to use it (nothing will be copied).
Select 'Yes' if you want to copy the Raspbian on your SD card to the USB device (everything will be copied).
If you select 'Yes', usb-boot will then prompt: 'Select the partition table type to use (MBR = 2TB Maximum)'
usb-boot will then prompt: 'All existing data on USB device /dev/sdX will be destroyed!' and ask: 'Do you wish to continue?'
If you select 'Yes', the copy will begin. The time required for this process will depend on the amount of data on your SD card and the speed of your storage devices.
usb-boot will then complete the configuration process and warn you of any potential conflicts it detects.
When usb-boot has finished, you should be able to reboot and be running Raspbian on the USB device (first power off and remove the SD card if not using the SD card to boot the USB device).
=====
sdc-boot provides a convenient way to select which attached device will be booted.
Usage syntax is:
sdc-boot [ /dev/sdX2 | /dev/mmcblk0p2 | hhhhhhhh-02 | hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh ]
/dev/sdX2 is a USB device
/dev/mmcblk0p2 is the SD card
hhhhhhhh-02 | hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh is a device identified by its PARTUUID
If no device is specified, the currently selected boot device will be displayed.
=====
GPT partition tables are necessary for devices whose size is over 2TB.
mbr2gpt converts an MBR partition table on a USB device to a GPT partition table, as well as optionally expanding the ROOT partition and enabling booting via an SD card.
mbr2gpt converts any size USB device, including SD cards placed in a USB adapter.
!!! DO NOT PROCEED UNLESS YOU HAVE A RELIABLE BACKUP OF THE DEVICE BEING CONVERTED !!!
!!! INITIAL TESTING SHOULD BE PERFORMED ON A USB DEVICE CONTAINING EXPENDABLE DATA !!!
Usage syntax is:
mbr2gpt /dev/sdX
mbr2gpt will prompt for permission to perform the following optional functions:
1. Convert the USB device to use GPT partition tables
2. Expand the ROOT partition to use all available space
3. Set the SD card to boot the USB device
=====
set-partuuid displays or changes the ROOT partition PARTUUID on a device.
Usage syntax is:
set-partuuid device [ hhhhhhhh-02 | hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh | random ]
device may be /dev/sdX2 or /dev/mmcblk0p2
If no partuuid is specified, the current ROOT partition PARTUUID will be displayed.