-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathapply_update.sh
More file actions
140 lines (106 loc) · 5.05 KB
/
apply_update.sh
File metadata and controls
140 lines (106 loc) · 5.05 KB
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
#!/bin/bash
# -- Globals --
update_mount_path="/mnt/rootfs" # Path where the updated root will temporarily be mounted
data_mount_path="/mnt/data"
update_file="$data_mount_path/rootfs.img.bz2"
# -- Helper Functions --
function print_line {
echo "[$(date +'%b %d %T') apply_update.sh]: $1"
}
function report_error {
print_line "ERROR: $1. Exiting."
exit 1
}
# -- Main Script --
# Perform some sanity checks first
print_line "Checking if script is running as root..."
if [[ "$EUID" -ne 0 ]]; then
report_error "Please run this script as root"
fi
# Check if data mount path is actually mounted to something
if [[ -z $(lsblk | grep "$data_mount_path") ]]; then
report_error "Nothing mounted to $data_mount_path"
fi
print_line "Downloading the update from '$1'..."
# Download the update image file
curl "$1" --output "$update_file" || report_error "Downloading '$1' failed"
if [ ! -f "$update_file" ]; then
report_error "Couldn't download to file $update_file"
fi
# Check if a checksum is provided
if [ -z "$2" ]; then
print_line "No checksum provided. This is a security risk."
else
print_line "Verifying SHA-256 checksum..."
sha256=$(sha256sum "$update_file" | awk '{print $1}')
if [[ "$sha256" != "$2" ]]; then
print_line "EXPECT: $2"
print_line "ACTUAL: $sha256"
echo "Removing $update_file"
rm "$update_file"
report_error "SHA-256 checksums do not match"
else
print_line "Verification successful"
fi
fi
active_partition_uuid=$(grep -o 'root=[^ ]*' /boot/cmdline.txt)
active_partition_uuid=${active_partition_uuid:5} # Ignore 'root=' in the beginning
active_partition_suffix=$(echo $active_partition_uuid | grep -o '.\{3\}$')
case $active_partition_suffix in
"-03")
update_partition="/dev/mmcblk0p2"
update_partition_suffix="-02"
;;
"-02")
update_partition="/dev/mmcblk0p3"
update_partition_suffix="-03"
;;
*)
report_error "Unknown active partition $active_partition_uuid"
;;
esac
update_partition_uuid=$(echo $active_partition_uuid | sed "s/$active_partition_suffix/$update_partition_suffix/")
print_line "active partition uuid=$active_partition_uuid suffix=$active_partition_suffix"
print_line "update partition uuid=$update_partition_uuid suffix=$update_partition_suffix"
print_line "The update will be installed on $update_partition"
if [[ -z $update_partition || -z $update_partition_suffix ]]; then
print_line "ERROR: Please check if two ext4 partitions (/dev/mmcblk0p2 and /dev/mmcblk0p3) of equal size are present"
report_error "Can't detect active and update partition"
fi
print_line "Starting in 5 secs..."
sleep 5
compression_type=${update_file##*.}
if [[ "$compression_type" != 'bz2' ]]; then
report_error "Image file $update_file is not compressed with bz2"
fi
# Get the name of uncompressed image file
img=${update_file%.img*}.img
print_line "Extracting $update_file to $img..."
# Extract using pbzip2 (uses multiple threads)
pbzip2 -f --verbose -d $update_file || report_error "Extraction failed."
# Confirm that the raw-image file is present
stat $img > /dev/null 2>&1 || report_error "Expected file '$img' not found"
print_line "Updating partition $update_partition..."
# Unmount the update partition. Not neccessary, but just in case...
umount $update_partition > /dev/null 2>&1
# Apply update
dd if=$img of=$update_partition bs=4M status=progress || report_error "Updating failed"
print_line "Mounting $update_partition to $update_mount_path"
mkdir -p $update_mount_path || report_error "Couldn't create path $update_mount_path for mounting"
mount $update_partition $update_mount_path || report_error "Couldn't mount $update_partition to $update_mount_path"
# Edit the fstab of the new root so that it mounts the update partition to root
print_line "Editing /etc/fstab of the updated image"
cp /etc/fstab "$update_mount_path/etc/fstab" || report_error "Couldn't update /etc/fstab of the new root partition"
# Find the line that mounts the currently active partition to root
current_root=$(grep -E '^\S+\s+\/\s+' "$update_mount_path/etc/fstab" | grep -v '^#')
# Replace it so that the updated partition is mounted to root
sed -i "/^$active_partition_uuid/d" "$update_mount_path/etc/fstab" || report_error "Couldn't modify /etc/fstab of the new root partition"
echo $current_root | sed "s/$active_partition_suffix/$update_partition_suffix/" >> "$update_mount_path/etc/fstab" || report_error "Couldn't write to the /etc/fstab of the new root partition"
print_line "Updating cmdline.txt (backup = /boot/cmdline.txt.bak)..."
# Create a backup of kernel parameters
cp /boot/cmdline.txt /boot/cmdline.txt.bak || report_error "Couldn't backup /boot/cmdline.txt"
# Configure the kernel parameters to consider the updated partition as root
sed -i "s/$active_partition_uuid/$update_partition_uuid/" /boot/cmdline.txt || report_error "Couldn't update /boot/cmdline.txt"
print_line "Deleting update image..."
rm -rf "$update_file" || print_line "WARNING: Couldn't remove update image file '$update_file'"
print_line "Update applied successfully"