-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
211 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,20 @@ | ||
# rpi2GPT | ||
Copy a raspiOS image to a GPT-partitioned device | ||
# rpi-img2GPT | ||
Copy a raspiOS disk image to a GPT-partitioned device (eg. hard disk) | ||
|
||
## Usage: | ||
``` | ||
sudo rpi-img2GPT -d|--device device_name -i|--image rpi_disk_image | ||
``` | ||
|
||
Example: | ||
|
||
sudo rpi-img2GPT --device /dev/sdc --image 2021-05-07-raspios-buster-armhf-lite.img | ||
|
||
## What the command does | ||
This command will: | ||
- Erase the specified device (usually a hard disk) | ||
- Partition the device with the GPT scheme and create 2 partitions - boot (64MB) and root (the rest of the device) | ||
- Copy the content of the disk image to the device | ||
- Change the file boot/config.txt to define a 2 x 5-second-delay to run the bootloader and kernel to leave enough time for the device to spin | ||
- Change the file boot/cmdline.txt to define the new root mount (switching in the process to PARTLABEL from PARTUUID) and remove the call to the initial root partition resize | ||
- Change the file root/etc/fstab to define the 2 mount points - /boot and / - (switching in the process to PARTLABEL from PARTUUID) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
#!/bin/bash | ||
|
||
DisplayUsage() { | ||
|
||
cat <<-EOF | ||
${COMMAND} copies a raspiOS disk image to a GPT-partitioned device and performs a few adjustments to allow the raspberry-pi to boot directly from the device. | ||
Usage: | ||
${COMMAND} --device|-d device_name --image|-i disk_image | ||
EOF | ||
|
||
exit 0 | ||
} | ||
|
||
GetArguments() { | ||
## Translate long options to short ones | ||
for arg in $@; do | ||
delim="" | ||
case ${arg} in | ||
"--help") args="${args}-h" ;; | ||
"--device") args="${args}-d" ;; | ||
"--image") args="${args}-i" ;; | ||
*) [[ "${arg:0:1}" == "-" ]] || delim="\"" | ||
args="${args}${delim}${arg}${delim} ";; | ||
esac | ||
done | ||
|
||
# reset the translated args | ||
eval set -- "${args}" | ||
|
||
## Parse short options | ||
while getopts "hd:i:" opt; do | ||
case ${opt} in | ||
"h") DisplayUsage; exit 0 ;; | ||
"d") DEVICE_NAME=${OPTARG} ;; | ||
"i") DISK_IMAGE=${OPTARG} ;; | ||
*) DisplayUsage ;; | ||
esac | ||
done | ||
} | ||
|
||
CheckConditions() { | ||
|
||
# Check that the program is run by root | ||
if [ $(id -u) -ne 0 ]; then | ||
echo "${COMMAND} must be run as root" >&2 | ||
exit 1 | ||
fi | ||
|
||
# Check that the device exists | ||
if [ -z ${DEVICE_NAME} ]; then | ||
echo "Device name not specified" >&2 | ||
exit 2 | ||
fi | ||
|
||
mountpoints=$(lsblk --noheadings --list -o MOUNTPOINTS ${DEVICE_NAME} 2>/dev/null) | ||
if [ ${?} -ne 0 ]; then | ||
echo "Device ${DEVICE_NAME} not found" >&2 | ||
exit 3 | ||
fi | ||
|
||
# Check that the disk image exists | ||
if [ -z ${DISK_IMAGE} ]; then | ||
echo "Disk image not specified" >&2 | ||
exit 4 | ||
fi | ||
|
||
if [ ! -f ${DISK_IMAGE} ]; then | ||
echo "Disk image ${DISK_IMAGE} not found" >&2 | ||
exit 5 | ||
fi | ||
} | ||
|
||
Cleanup() { | ||
|
||
echo "Cleaning up..." | ||
# Unmount partitions | ||
umount ${TEMP_DIR}/* | ||
|
||
# Unmap disk image | ||
kpartx -d ${DISK_IMAGE} | ||
|
||
# Delete the temporary directory | ||
if [ -d ${TEMP_DIR} ]; then | ||
rm -rf ${TEMP_DIR} | ||
fi | ||
} | ||
|
||
# Initialize the program | ||
|
||
## Set constants | ||
readonly COMMAND=$(basename ${0}) | ||
|
||
## Get arguments | ||
GetArguments $@ | ||
|
||
## Check conditions | ||
CheckConditions | ||
|
||
## Set program execution flags | ||
set -euo pipefail | ||
|
||
## Intercept interruptions | ||
trap Cleanup SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM | ||
|
||
# STEP-1: Prepare the hard disk | ||
## unmount the partitions of the specified device, if any | ||
for mp in ${mountpoints}; do | ||
umount ${mp} | ||
done | ||
|
||
## Remove previous content | ||
echo "Erasing device ${DEVICE_NAME}..." | ||
sgdisk --zap-all ${DEVICE_NAME} 1>/dev/null | ||
|
||
## Create 2 partitions | ||
echo "Preparing device ${DEVICE_NAME}..." | ||
sgdisk --new=0:0:+64M --typecode=0:0700 --change-name=0:boot ${DEVICE_NAME} 1>/dev/null | ||
sgdisk --new=0:0:0 --typecode=0:8300 --change-name=0:root ${DEVICE_NAME} 1>/dev/null | ||
|
||
## Create an hybrid MBR with partition type "0c" so that bootloader finds it | ||
cat << EOF | gdisk ${DEVICE_NAME} 1>/dev/null | ||
r | ||
h | ||
1 | ||
N | ||
0c | ||
N | ||
Y | ||
EE | ||
w | ||
Y | ||
EOF | ||
|
||
## Format the 3 partitions | ||
mkfs.fat -F 32 -n BOOT ${DEVICE_NAME}1 1>/dev/null 2>&1 | ||
mkfs.ext4 -F -L root ${DEVICE_NAME}2 1>/dev/null | ||
|
||
# STEP-2: Copy the content of the disk image to the hard disk | ||
## Create a temporary directory | ||
readonly TEMP_DIR=$(mktemp -d) | ||
|
||
## Mount the 2 hard-disk partitions | ||
mkdir ${TEMP_DIR}/d1 | ||
mount ${DEVICE_NAME}1 ${TEMP_DIR}/d1 | ||
mkdir ${TEMP_DIR}/d2 | ||
mount ${DEVICE_NAME}2 ${TEMP_DIR}/d2 | ||
|
||
## Map the disk image to a loop device | ||
readonly LIST_MAPPINGS=$(kpartx -asv ${DISK_IMAGE}) | ||
|
||
## Mount the 2 disk image partitions | ||
device=$(echo ${LIST_MAPPINGS} | cut -d" " -f3) | ||
mkdir ${TEMP_DIR}/s1 | ||
mount /dev/mapper/${device} ${TEMP_DIR}/s1 | ||
|
||
device=$(echo ${LIST_MAPPINGS} | cut -d" " -f12) | ||
mkdir ${TEMP_DIR}/s2 | ||
mount /dev/mapper/${device} ${TEMP_DIR}/s2 | ||
|
||
## Copy content of the disk image to the device | ||
echo "Copying boot-partition files..." | ||
rsync -a ${TEMP_DIR}/s1/ ${TEMP_DIR}/d1 | ||
echo "Copying root-partition files..." | ||
rsync -a ${TEMP_DIR}/s2/ ${TEMP_DIR}/d2 | ||
|
||
# STEP-3: adjust some settings | ||
|
||
## /boot/config.txt: Add bootcode_delay and boot_delay | ||
echo "Making few adjustments..." | ||
echo 'bootcode_delay=5' >> ${TEMP_DIR}/d1/config.txt | ||
echo 'boot_delay=5' >> ${TEMP_DIR}/d1/config.txt | ||
|
||
## /boot/cmdline.txt: Remove one-time root file system resizing, quiet option and fsck option | ||
sed -e 's; init=/usr/lib/raspi-config/init_resize.sh;;' -i ${TEMP_DIR}/d1/cmdline.txt | ||
sed -e 's; quiet;;' -i ${TEMP_DIR}/d1/cmdline.txt | ||
sed -e 's; fsck.repair=yes; fsck.repair=no;' -i ${TEMP_DIR}/d1/cmdline.txt | ||
|
||
## Change mount point in /boot/cmdline.txt | ||
sed -e 's;root=PARTUUID=[0-9,a-f,\-]*;root=PARTLABEL=root;' -i ${TEMP_DIR}/d1/cmdline.txt | ||
|
||
## Change mount points in /etc/fstab | ||
sed -e 's;^PARTUUID=.*/boot;PARTLABEL=boot \t/boot;' -i ${TEMP_DIR}/d2/etc/fstab | ||
sed -e 's;^PARTUUID=.*/[[:blank:]];PARTLABEL=root \t/;' -i ${TEMP_DIR}/d2/etc/fstab | ||
|
||
# Clean up and exit | ||
Cleanup | ||
echo "Operation completed" | ||
exit 0 |