Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(483)

Side by Side Diff: src/platform/installer/chromeos-common.sh

Issue 1100001: Switch to GPT-format disk images. (Closed)
Patch Set: Final GPT-enabling changeset. I hope. Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/platform/init/chromeos_startup ('k') | src/platform/installer/chromeos-install » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 #
5 # This contains common constants and functions for installer scripts. This must
6 # evaluate properly for both /bin/bash and /bin/sh, since it's used both to
7 # create the initial image at compile time and to install or upgrade a running
8 # image.
9
10 # Here are the GUIDs we'll be using to identify various partitions.
11 STATEFUL_GUID='ebd0a0a2-b9e5-4433-87c0-68b6b72699c7'
12 KERN_GUID='fe3a2a5d-4f32-41a7-b725-accc3285a309'
13 ROOTFS_GUID='3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec'
14 ESP_GUID='28732ac1-1ff8-d211-ba4b-00a0c93ec93b'
15
16
17 # The GPT tables describe things in terms of 512-byte sectors, but some
18 # filesystems prefer 4096-byte blocks. These functions help with alignment
19 # issues.
20
21 # This returns the size of a file or device in 512-byte sectors, rounded up if
22 # needed.
23 # Invoke as: subshell
24 # Args: FILENAME
25 # Return: whole number of sectors needed to fully contain FILENAME
26 numsectors() {
27 case $1 in
28 /dev/*[0-9])
29 dnum=${1##*/}
30 dev=${dnum%%[0-9]*}
31 cat /sys/block/$dev/$dnum/size
32 ;;
33 /dev/*)
34 dev=${1##*/}
35 cat /sys/block/$dev/size
36 ;;
37 *)
38 local bytes=$(stat -c%s "$1")
39 local sectors=$(( $bytes / 512 ))
40 local rem=$(( $bytes % 512 ))
41 if [ $rem -ne 0 ]; then
42 sectors=$(( $sectors + 1 ))
43 fi
44 echo $sectors
45 ;;
46 esac
47 }
48
49 # Round a number of 512-byte sectors up to an integral number of 4096-byte
50 # blocks.
51 # Invoke as: subshell
52 # Args: SECTORS
53 # Return: Next largest multiple-of-8 sectors (ex: 4->8, 33->40, 32->32)
54 roundup() {
55 local num=$1
56 local rem=$(( $num % 8 ))
57
58 if (( $rem )); then
59 num=$(($num + 8 - $rem))
60 fi
61 echo $num
62 }
63
64 # Truncate a number of 512-byte sectors down to an integral number of 4096-byte
65 # blocks.
66 # Invoke as: subshell
67 # Args: SECTORS
68 # Return: Next smallest multiple-of-8 sectors (ex: 4->0, 33->32, 32->32)
69 rounddown() {
70 local num=$1
71 local rem=$(( $num % 8 ))
72
73 if (( $rem )); then
74 num=$(($num - $rem))
75 fi
76 echo $num
77 }
78
79
80 # We need to locate the gpt tool. It should already be installed in the build
81 # chroot, but some of these functions may be invoked outside the chroot (by
82 # image_to_usb or similar), so we need to find it.
83 GPT=$(which gpt 2>/dev/null) || /bin/true
84 if [ -z "$GPT" ]; then
85 if [ -x "${DEFAULT_CHROOT_DIR:-}/usr/bin/gpt" ]; then
86 GPT="${DEFAULT_CHROOT_DIR:-}/usr/bin/gpt"
87 else
88 echo "can't find gpt tool" 1>&2
89 exit 1
90 fi
91 fi
92
93
94 # This installs a GPT into the specified device or file, using the given
95 # components. If the target is a block device we'll do a full install.
96 # Otherwise, it'll be just enough to boot.
97 # Invoke as: command (not subshell)
98 # Args: TARGET ROOTFS_IMG KERNEL_IMG STATEFUL_IMG PMBRCODE
99 # Return: nothing
100 # Side effects: Sets these global variables describing the GPT partitions
101 # (all untis are 512-byte sectors):
102 # NUM_KERN_SECTORS
103 # NUM_ROOTFS_SECTORS
104 # NUM_STATEFUL_SECTORS
105 # NUM_RESERVED_SECTORS
106 # START_KERN_A
107 # START_STATEFUL
108 # START_ROOTFS_A
109 # START_KERN_B
110 # START_ROOTFS_B
111 # START_RESERVED
112 install_gpt() {
113 local outdev=$1
114 local rootfs_img=$2
115 local kernel_img=$3
116 local stateful_img=$4
117 local pmbrcode=$5
118
119 # The gpt tool requires a fixed-size target to work on, so we may have to
120 # create a file of the appropriate size. Let's figure out what that size is
121 # now. The partition layout is gonna look something like this:
122 #
123 # PMBR (512 bytes)
124 # Primary GPT Header (512 bytes)
125 # Primary GPT Table (16K)
126 # Kernel A partition 2
127 # Kernel B partition 4
128 # reserved space for additional partitions partition 6,7,8,...
129 # Stateful partition (as large as possible) partition 1
130 # Rootfs B partition 5
131 # Rootfs A partition 3
132 # Secondary GPT Table (16K)
133 # Secondary GPT Header (512 bytes)
134 #
135 # Please refer to the official ChromeOS documentation for the details and
136 # explanation behind the layout and partition numbering scheme. The short
137 # version is that 1) we want everything above partition 3 to be optional when
138 # we're creating a bootable USB key, 2) we want to be able to add new
139 # partitions later without breaking current scripts, and 3) we may need to
140 # increase the size of the rootfs during an upgrade, which means shrinking
141 # the size of the stateful partition.
142 #
143 # One nonobvious contraint is that the ext2-based filesystems typically use
144 # 4096-byte blocks. We'll need a little padding at each end of the disk to
145 # align the useable space to that size boundary.
146
147 # Here are the size limits that we're currently requiring
148 local max_kern_sectors=32768 # 16M
149 local max_rootfs_sectors=2097152 # 1G
150 local max_reserved_sectors=131072 # 64M
151 local min_stateful_sectors=262144 # 128M, expands to fill available space
152
153 local num_pmbr_sectors=1
154 local num_gpt_hdr_sectors=1
155 local num_gpt_table_sectors=32 # 16K
156 local num_footer_sectors=$(($num_gpt_hdr_sectors + $num_gpt_table_sectors))
157 local num_header_sectors=$(($num_pmbr_sectors + $num_footer_sectors))
158
159 local start_useful=$(roundup $num_header_sectors)
160
161 # What are we doing?
162 if [ -b $outdev ]; then
163 # Block device, need to be root.
164 local sudo=sudo
165
166 # Full install, use max sizes and create both A & B images.
167 NUM_KERN_SECTORS=$max_kern_sectors
168 NUM_ROOTFS_SECTORS=$max_rootfs_sectors
169 NUM_RESERVED_SECTORS=$max_reserved_sectors
170
171 # Where do things go?
172 START_KERN_A=$start_useful
173 START_KERN_B=$(($START_KERN_A + $NUM_KERN_SECTORS))
174 START_RESERVED=$(($START_KERN_B + $NUM_KERN_SECTORS))
175 START_STATEFUL=$(($START_RESERVED + $NUM_RESERVED_SECTORS))
176
177 local total_sectors=$(numsectors $outdev)
178 local start_gpt_footer=$(($total_sectors - $num_footer_sectors))
179 local end_useful=$(rounddown $start_gpt_footer)
180
181 START_ROOTFS_A=$(($end_useful - $NUM_ROOTFS_SECTORS))
182 START_ROOTFS_B=$(($START_ROOTFS_A - $NUM_ROOTFS_SECTORS))
183
184 NUM_STATEFUL_SECTORS=$(($START_ROOTFS_B - $START_STATEFUL))
185 else
186 # Just a local file.
187 local sudo=
188
189 # We'll only populate partitions 1, 2, 3. Image B isn't required for this,
190 # and the others are still theoretical.
191 NUM_KERN_SECTORS=$(roundup $(numsectors $kernel_img))
192 NUM_ROOTFS_SECTORS=$(roundup $(numsectors $rootfs_img))
193 NUM_STATEFUL_SECTORS=$(roundup $(numsectors $stateful_img))
194 NUM_RESERVED_SECTORS=0
195
196 START_KERN_A=$start_useful
197 START_STATEFUL=$(($START_KERN_A + $NUM_KERN_SECTORS))
198 START_ROOTFS_A=$(($START_STATEFUL + $NUM_STATEFUL_SECTORS))
199 START_KERN_B=""
200 START_ROOTFS_B=""
201 START_RESERVED=""
202
203 # For minimal install, we're not worried about the secondary GPT header
204 # being at the end of the device because we're almost always writing to a
205 # file. If that's not true, the secondary will just be invalid.
206 local start_gpt_footer=$(($START_ROOTFS_A + $NUM_ROOTFS_SECTORS))
207 local end_useful=$start_gpt_footer
208
209 local total_sectors=$(($start_gpt_footer + $num_footer_sectors))
210
211 # Create the image file if it doesn't exist.
212 if [ ! -e ${outdev} ]; then
213 dd if=/dev/zero of=${outdev} bs=512 count=1 seek=$(($total_sectors - 1))
214 fi
215 fi
216
217 echo "Creating partition tables..."
218
219 # Zap any old partitions (otherwise gpt complains).
220 $sudo dd if=/dev/zero of=${outdev} conv=notrunc bs=512 \
221 count=$num_header_sectors
222 $sudo dd if=/dev/zero of=${outdev} conv=notrunc bs=512 \
223 seek=${start_gpt_footer} count=$num_footer_sectors
224
225 # Create the new GPT partitions. The order determines the partition number.
226 # Note that the partition label is in the GPT only. The filesystem label is
227 # what's used to populate /dev/disk/by-label/, and this is not that.
228 $sudo $GPT create ${outdev}
229
230 $sudo $GPT add -b ${START_STATEFUL} -s ${NUM_STATEFUL_SECTORS} \
231 -t ${STATEFUL_GUID} ${outdev}
232 $sudo $GPT label -i 1 -l "STATE" ${outdev}
233
234 $sudo $GPT add -b ${START_KERN_A} -s ${NUM_KERN_SECTORS} \
235 -t ${KERN_GUID} ${outdev}
236 $sudo $GPT label -i 2 -l "KERN-A" ${outdev}
237
238 $sudo $GPT add -b ${START_ROOTFS_A} -s ${NUM_ROOTFS_SECTORS} \
239 -t ${ROOTFS_GUID} ${outdev}
240 $sudo $GPT label -i 3 -l "ROOT-A" ${outdev}
241
242 # add the rest of the partitions for a full install
243 if [ -n "$START_KERN_B" ]; then
244 $sudo $GPT add -b ${START_KERN_B} -s ${NUM_KERN_SECTORS} \
245 -t ${KERN_GUID} ${outdev}
246 $sudo $GPT label -i 4 -l "KERN-B" ${outdev}
247
248 $sudo $GPT add -b ${START_ROOTFS_B} -s ${NUM_ROOTFS_SECTORS} \
249 -t ${ROOTFS_GUID} ${outdev}
250 $sudo $GPT label -i 5 -l "ROOT-B" ${outdev}
251 fi
252
253 # Create the PMBR and instruct it to boot ROOT-A
254 $sudo $GPT boot -i 3 -b ${pmbrcode} ${outdev}
255
256 # Display what we've got
257 $sudo $GPT -r show -l ${outdev}
258
259 sync
260 }
261
262
263 # Helper function, please ignore and look below.
264 _partinfo() {
265 local device=$1
266 local partnum=$2
267 local start size part x n
268 sudo $GPT -r -S show $device \
269 | grep 'GPT part -' \
270 | while read start size part x x x n x; do \
271 if [ "${part}" -eq "${partnum}" ]; then \
272 echo $start $size; \
273 fi; \
274 done
275 # The 'while' is a subshell, so there's no way to indicate success.
276 }
277
278 # Read GPT table to find information about a specific partition.
279 # Invoke as: subshell
280 # Args: DEVICE PARTNUM
281 # Returns: offset and size (in sectors) of partition PARTNUM
282 partinfo() {
283 # get string
284 local X=$(_partinfo $1 $2)
285 # detect success or failure here
286 [ -n "$X" ] && echo $X
287 }
288
289 # Read GPT table to find the starting location of a specific partition.
290 # Invoke as: subshell
291 # Args: DEVICE PARTNUM
292 # Returns: offset (in sectors) of partition PARTNUM
293 partoffset() {
294 # get string
295 local X=$(_partinfo $1 $2)
296 # detect success or failure here
297 [ -n "$X" ] && echo ${X% *}
adlr 2010/03/30 19:50:20 same here?
298 }
299
300 # Read GPT table to find the size of a specific partition.
301 # Invoke as: subshell
302 # Args: DEVICE PARTNUM
303 # Returns: size (in sectors) of partition PARTNUM
304 partsize() {
305 # get string
306 local X=$(_partinfo $1 $2)
307 # detect success or failure here
308 [ -n "$X" ] && echo ${X#* }
adlr 2010/03/30 19:50:20 same here?
309 }
310
OLDNEW
« no previous file with comments | « src/platform/init/chromeos_startup ('k') | src/platform/installer/chromeos-install » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698