forked from adafruit/Adafruit-Pi-ExternalRoot-Helper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
adafruit-pi-externalroot-helper
executable file
·149 lines (125 loc) · 4.91 KB
/
adafruit-pi-externalroot-helper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env bash
# adafruit-pi-externalroot-helper
#
# Configure a Raspbian system to use an external USB drive as root filesystem.
#
# See README.md for details and sources.
set -e
function print_version() {
echo "Adafruit Pi External Root Helper v0.1.0"
exit 1
}
function print_help() {
echo "Usage: $0 -d [target device]"
echo " -h Print this help"
echo " -v Print version information"
echo " -d [device] Specify path of device to convert to root"
echo
echo "You must specify a device. See:"
echo "https://learn.adafruit.com/external-drive-as-raspberry-pi-root"
exit 1
}
# Display an error message and quit:
function bail() {
FG="1;31m"
BG="40m"
echo -en "[\033[${FG}\033[${BG}error\033[0m] "
echo "$*"
exit 1
}
# Display an info message:
function info() {
task="$1"
shift
FG="1;32m"
BG="40m"
echo -e "[\033[${FG}\033[${BG}${task}\033[0m] $*"
}
if [[ $EUID -ne 0 ]]; then
bail "must be run as root. try: sudo adafruit-pi-externalroot-helper"
fi
# Handle arguments:
args=$(getopt -uo 'hvd:' -- $*)
[ $? != 0 ] && print_help
set -- $args
for i
do
case "$i"
in
-h)
print_help
;;
-v)
print_version
;;
-d)
target_drive="$2"
echo "Target drive = ${2}"
shift
shift
;;
esac
done
if [[ ! -e "$target_drive" ]]; then
bail "Target ${target_drive} must be existing device (use -d /dev/foo to specify)"
fi
info "start" "Will create new ext4 filesystem on ${target_drive}"
info "start" "If there is data on ${target_drive}, it will be lost."
read -p "Really proceed? (y)es / (n)o " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo "Quitting."
exit
fi
export target_partition="${target_drive}1"
info "dependencies" "Installing gdisk, rsync, and parted."
# All except gdisk are probably installed, but let's make sure.
apt-get install gdisk rsync parted
info "fs create" "Creating ${target_partition}"
# The alternative here seems to be to pipe a series of commands
# to fdisk(1), similar to how it's done by raspi-config:
# https://github.com/asb/raspi-config/blob/3a5d75340a1f9fe5d7eebfb28fee0e24033f4fd3/raspi-config#L68
# This seemed to work, but I was running into weirdness because
# that doesn't seem to make a GPT, and later on I couldn't get
# partition unique GUID from gdisk. parted(1) is also a nice
# option because it's scriptable and allows partition sizes to
# be specified in percentages.
parted --script "${target_drive}" mklabel gpt
parted --script --align optimal "${target_drive}" mkpart primary ext4 0% 100%
info "fs create" "Creating ext4 filesystem on ${target_partition}"
mkfs -t ext4 -L rootfs "${target_partition}"
info "fs id" "Getting UUID for target partition"
eval `blkid -o export "${target_partition}"`
export target_partition_uuid=$UUID
info "fs id" "Getting Partition unique GUID for target filesystem"
# Ok, so the only way I was able to get this was using gdisk.
# I don't quite understand the different between this value and
# the one you can get with blkid and tune2fs (which seem to give
# the same thing). Nevertheless, this seems to be necessary to
# get a value that can be used in cmdline.txt. I think it's a
# GUID specifically for the GPT partition table entry.
export partition_unique_guid=`echo 'i' | sudo gdisk "${target_drive}" | grep 'Partition unique GUID:' | awk '{print $4}'`
info "fs id" "Target partition UUID: ${target_partition_uuid}"
info "fs id" "Partition unique GUID: ${partition_unique_guid}"
info "fs copy" "Mounting ${target_partition} on /mnt"
mount "${target_partition}" /mnt
info "fs copy" "Copying root filesystem to ${target_partition} with rsync"
info "fs copy" "This will take quite a while. Please be patient!"
rsync -ax / /mnt
info "boot config" "Configuring boot from {$target_partition}"
# rootdelay=5 is likely not necessary here, but seems to do no harm.
cp /boot/cmdline.txt /boot/cmdline.txt.bak
sed -i "s|root=\/dev\/mmcblk0p2|root=PARTUUID=${partition_unique_guid} rootdelay=5|" /boot/cmdline.txt
info "boot config" "Commenting out old root partition in /etc/fstab, adding new one"
# These changes are made on the new drive after copying so that they
# don't have to be undone in order to switch back to booting from the
# SD card.
sed -i '/mmcblk0p2/s/^/#/' /mnt/etc/fstab
echo "/dev/disk/by-uuid/${target_partition_uuid} / ext4 defaults,noatime 0 1" >> /mnt/etc/fstab
info "boot config" "Ok, your system should be ready. You may wish to check:"
info "boot config" " /mnt/etc/fstab"
info "boot config" " /boot/cmdline.txt"
info "boot config" "Your new root drive is currently accessible under /mnt."
info "boot config" "In order to restart with this drive at /, please type:"
info "boot config" "sudo reboot"