-
Notifications
You must be signed in to change notification settings - Fork 1
/
100_include_partition_code.sh
378 lines (334 loc) · 16.1 KB
/
100_include_partition_code.sh
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# Generate code to partition the disks.
# The parted command is mandatory,
# see https://github.com/rear/rear/issues/1933#issuecomment-430207057
has_binary parted || Error "Cannot find 'parted' command"
#
# TODO: clean up that old code when parted doesn't support any unit.
# It's there since ages!
#
# True if parted accepts values in units other than mebibytes.
FEATURE_PARTED_ANYUNIT=
# Test by using the parted version numbers...
parted_version=$( get_version parted -v )
test "$parted_version" || BugError "Function get_version could not detect parted version"
if version_newer "$parted_version" 1.6.23 ; then
FEATURE_PARTED_ANYUNIT="y"
fi
### Prepare a disk for partitioning/general usage.
create_disk() {
local component disk size label extrafields
read component disk size label extrafields < <(grep "^disk $1 " "$LAYOUT_FILE")
cat >> "$LAYOUT_CODE" <<EOF
#
# Code handling disk '$disk'
#
### Disks should be block devices.
[ -b "$disk" ] || BugError "Disk $disk is not a block device."
Log "Stop mdadm"
if grep -q md /proc/mdstat 2>/dev/null; then
mdadm --stop -s >&2 || echo "stop mdadm failed"
# Prevent udev waking up mdadm later.
# Reasoning: At least on RHEL6 when parted created a raid partition on disk,
# udev (via /lib/udev/rules.d/65-md-incremental.rules) wakes up mdadm which locks the disk,
# so further parted commands with the disk will fail since the disk is busy now.
# The /lib/udev/rules.d/65-md-incremental.rules detects anaconda (the Red Hat installer),
# and if it find itself running under anaconda, it will not run.
# Accordingly also for other installers (in particular the ReaR installer)
# this rule should not be there (and other Linux distros probably do not have it)
# which means removing it is the right solution to make ReaR work also for RHEL6:
if [ -e /lib/udev/rules.d/65-md-incremental.rules ] ; then
rm -f /lib/udev/rules.d/65-md-incremental.rules || echo "rm 65-md-incremental.rules failed"
fi
fi
Log "Erasing MBR of disk $disk"
dd if=/dev/zero of=$disk bs=512 count=1
sync
EOF
# $extrafields can contain useful DASD-specific fields
create_partitions "$disk" "$label" "$extrafields"
cat >> "$LAYOUT_CODE" <<EOF
# Make sure device nodes are visible (eg. in RHEL4)
my_udevtrigger
my_udevsettle
# Clean up transient partitions and resize shrinked ones
delete_dummy_partitions_and_resize_real_ones
#
# End of code handling disk '$disk'
#
EOF
}
### Create partitions on a block device.
### The block device does not necessarily exist yet...
create_partitions() {
local device=$1
local label=$2
### List partition types/names to detect disk label type.
local -a names=()
local part disk size pstart name junk
local orig_block_size layout dasdtype dasdcyls junk2
if [ "$label" == dasd ]; then
# dasd has more fields - they are all in $3 now
read orig_block_size layout dasdtype dasdcyls junk2 <<<$3
fi
while read part disk size pstart name junk ; do
names+=( $name )
case $name in
(primary|extended|logical)
if [[ -z "$label" ]] ; then
Log "Disk label for $device detected as msdos."
label="msdos"
fi
;;
esac
done < <( grep "^part $device " "$LAYOUT_FILE" )
### Early return for devices without partitions.
if [[ ${#names[@]} -eq 0 ]] ; then
Log "No partitions on device $device."
return 0
fi
if [[ -z "$label" ]] ; then
label="gpt"
### msdos label types are detected earlier.
fi
# For the SUSE specific gpt_sync_mbr partitioning scheme
# see https://github.com/rear/rear/issues/544
# For 'gpt_sync_mbr' labeled disks create_partitions was called e.g. as
# create_partitions /dev/sda gpt_sync_mbr
# so that $label is not empty but still set to 'gpt_sync_mbr' here.
cat >> "$LAYOUT_CODE" <<EOF
create_disk_label $device $label
EOF
# There are certrain conditions below that test for AUTORESIZE_PARTITIONS
# but all what belongs to autoresizing partitions must only happen in MIGRATION_MODE:
local autoresize_partitions=""
is_true "$MIGRATION_MODE" && autoresize_partitions="$AUTORESIZE_PARTITIONS"
local block_size device_size sysfs_name
if [[ -b $device ]] ; then
sysfs_name=$(get_sysfs_name "$device")
if [[ "$sysfs_name" ]] && [[ -d "/sys/block/$sysfs_name" ]] ; then
block_size=$( get_block_size "$sysfs_name" )
device_size=$( get_disk_size "$sysfs_name" )
### GPT disks need 33 LBA blocks at the end of the disk
# For the SUSE specific gpt_sync_mbr partitioning scheme
# see https://github.com/rear/rear/issues/544
# see https://github.com/rear/rear/pull/2142 for s390 partitioning
#if [[ "$label" == "gpt" || "$label" == "gpt_sync_mbr" || "$label" == "dasd" ]] ; then
if [[ "$label" == "gpt" || "$label" == "gpt_sync_mbr" ]] ; then
device_size=$( mathlib_calculate "$device_size - 33*$block_size" )
# Only if resizing all partitions is explicity wanted
# resizing of arbitrary partitions may also happen via the code below
# in addition to layout/prepare/default/430_autoresize_all_partitions.sh
if is_true "$autoresize_partitions" ; then
Log "Size reductions of GPT partitions probably needed."
fi
fi
fi
fi
local start end start_mb end_mb number last_number
# let start=32768 # start after one cylinder 63*512 + multiple of 4k = 64*512
let start=2097152 # start after cylinder 4096*512 (for grub2 - see issue #492)
let end=0
let last_number=0
local flags partition
while read part disk size pstart name flags partition junk; do
# Get the partition number from the name
number=$( get_partition_number "$partition" )
# Because parted creates partitions starting at number 1 consecutively,
# we expect the partition numbers to be increasing. Failing to do so
# will make the parted command setting the file system type die in
# error.
if [[ $number -lt $last_number ]] ; then
# Admin probably reordered entries in disklayout.conf, die
Error "Device '$disk': partitions are not defined in expected order (partitions must be specified in ascending number)"
elif [[ $number -eq $last_number ]] ; then
Error "Device '$disk': partition with number $number is already defined"
elif [[ $( mathlib_calculate "$number - $last_number" ) -gt 1 ]] && [[ -z "$FEATURE_PARTED_ANYUNIT" ]] ; then
Error "Device '$disk': there are gaps between partitions, this is not supported"
fi
let last_number=$number
# In layout/save/GNU/Linux/200_partition_layout.sh
# in particular a GPT partition name that can contain spaces
# like 'EFI System Partition' cf. https://github.com/rear/rear/issues/1563
# was stored as a percent-encoded string in disklayout.conf
# so that here it needs to be percent-decoded:
name=$( percent_decode "$name" )
# Use the partition start value in disklayout.conf
# unless resizing all partitions is explicity wanted:
if ! is_true "$autoresize_partitions" && test "$pstart" != "unknown" ; then
start="$pstart"
fi
end=$(( start + size ))
### Test to make sure we're not past the end of the disk.
if [[ "$device_size" ]] && (( end > $device_size )) ; then
LogPrint "Partition $name on $device: size reduced to fit on disk."
Log "End changed from $end to $device_size."
end="$device_size"
fi
# Extended partitions run to the end of disk (we assume)
# only if resizing all partitions is explicity wanted:
if is_true "$autoresize_partitions" ; then
if [[ "$name" = "extended" ]] ; then
if [[ "$device_size" ]] ; then
end="$device_size"
else
### We don't know the size of devices that don't exist yet
### replaced by "100%" later on.
end=
fi
fi
fi
# Avoid naming multiple partitions "rear-noname" as this will trigger systemd log messages
# "Dev dev-disk-by\x2dpartlabel-rear\x2dnoname.device appeared twice with different sysfs paths"
if [[ "$name" == "rear-noname" ]] ; then
name="$(basename "$partition")"
fi
if [[ "$FEATURE_PARTED_ANYUNIT" ]] ; then
if [[ "$end" ]] ; then
end=$( mathlib_calculate "$end - 1" )
fi
if [[ "$ARCH" == "Linux-s390" && "$label" == dasd ]] ; then
# LDL formatted disks are already partitioned and should not be partitioned with parted or fdasd , it will fail
if [ "$layout" == LDL ]; then
Debug "$device: LDL formatted DASD, do not create a partition"
else
Debug "$device: ${layout} formatted DASD, create a partition"
cat >> "$LAYOUT_CODE" <<EOF
create_disk_partition "$device" "$name" $number $start $end
EOF
fi
else
# default case when $ARCH is not "Linux-s390":
cat >> "$LAYOUT_CODE" <<EOF
create_disk_partition "$device" "$name" $number $start $end
EOF
fi
else
### Old versions of parted accept only sizes in megabytes...
if (( $start > 0 )) ; then
start_mb=$( mathlib_calculate "$start / 1024 / 1024" )
else
start_mb=0
fi
end_mb=$( mathlib_calculate "$end / 1024 / 1024" )
# The duplicated quoting "'$name'" is there because
# parted's internal parser needs single quotes for values with blanks.
# In particular a GPT partition name that can contain spaces
# like 'EFI System Partition' cf. https://github.com/rear/rear/issues/1563
# so that when calling parted on command line it must be done like
# parted -s /dev/sdb unit MiB mkpart "'partition name'" 12 34
# where the outer quoting "..." is for bash so that
# the inner quoting '...' is preserved for parted's internal parser:
cat >> "$LAYOUT_CODE" <<EOF
my_udevsettle
parted -s $device mkpart "'$name'" $start_mb $end_mb >&2
my_udevsettle
EOF
fi
# Only if resizing all partitions is explicity wanted
# the start of the next partition is where this one ends.
# We can't use $end for extended partitions
# extended partitions have a small actual size as reported by sysfs
# but this issue is meanwhile fixed via https://github.com/rear/rear/pull/1733 by
# https://github.com/rear/rear/pull/1733/commits/6efb681d8b4c6a4d9f20b2900bbea79548c624a8
# Additionally in front of a logical partition should be at least 512B empty space
# which is probably wrong because certain places in the Internet mention a required gap
# of at least 63 sectors (63 * 512 bytes) between extended partition and logical partition
# e.g. cf. the German Wikipedia article about Master Boot Record that reads (excerpts):
# Primaere und erweiterte Partitionstabelle
# ...
# Alte Betriebssysteme erwarten den Start einer Partition immer an den Zylindergrenzen.
# Daher ergibt sich auch heute noch bei verbreiteten Betriebssystemen eine Luecke
# von 63 Sektoren zwischen erweiterter Partitionstabelle und dem Startsektor
# der entsprechenden logischen Partition.
if is_true "$autoresize_partitions" && test "$name" = "logical" ; then
# Without analysis I <jsmeix@suse.de> think by plain looking at the code
# that this '+ $block_size' results bad alignment because it usually adds 512B
# to the 'small actual size as reported by sysfs' which is e.g. 2 * 512B
# so that the result is the original start of disklayout.conf + 3 * 512B
# i.e. a new partition alignment to '3 * 512B' units:
start=$( mathlib_calculate "$start + ${size%B} + $block_size" )
else
start=$( mathlib_calculate "$start + ${size%B}" )
fi
# round starting size to next multiple of 4096
# 4096 is a good match for most device's block size
# only if resizing all partitions is explicity wanted:
if is_true "$autoresize_partitions" ; then
start=$(( $start + 4096 - ( $start % 4096 ) ))
fi
local flags="$( echo $flags | tr ',' ' ' )"
local flag
for flag in $flags ; do
if [[ "$flag" = "none" ]] ; then
continue
fi
(
echo "my_udevsettle"
echo "parted -s $device set $number $flag on >&2"
echo "my_udevsettle"
) >> $LAYOUT_CODE
done
# Explicitly name GPT partitions.
# For the SUSE specific gpt_sync_mbr partitioning scheme
# see https://github.com/rear/rear/issues/544
# The quoted duplicated quoting \"'$name'\" is there because
# parted's internal parser needs single quotes for values with blanks.
# In particular a GPT partition name that can contain spaces
# like 'EFI System Partition' cf. https://github.com/rear/rear/issues/1563
# so that when calling parted on command line it must be done like
# parted -s /dev/sdb unit MiB mkpart "'partition name'" 12 34
# where the outer quoting "..." is for bash which neeeds to be quoted \"...\" here
# because there is a outermost quoting "..." of the echo command
# and the inner quoting '...' is preserved for parted's internal parser:
if [[ "$label" = "gpt" || "$label" == "gpt_sync_mbr" ]] && [[ "$name" != "rear-noname" ]] ; then
(
echo "my_udevsettle"
echo "parted -s $device name $number \"'$name'\" >&2"
echo "my_udevsettle"
) >> $LAYOUT_CODE
fi
done < <(grep "^part $device " $LAYOUT_FILE)
# This will override all partition setup previously made,
# and create exact copy of original disk layout
# (ugly, ugly, ugly, but works)
# TODO: add code for GPT
if is_true "$BLOCKCLONE_STRICT_PARTITIONING" && [ -n "$BLOCKCLONE_SAVE_MBR_DEV" ]; then
(
echo ""
echo "# WARNING:"
echo "# This code will overwrite all partition changes previously made."
echo "# If you want avoid this, set BLOCKCLONE_STRICT_PARTITIONING=\"no\""
echo "sfdisk $device < $VAR_DIR/layout/$BLOCKCLONE_PARTITIONS_CONF_FILE"
echo "dd if=$VAR_DIR/layout/$BLOCKCLONE_MBR_FILE of=$device bs=446 count=1"
echo ""
) >> "$LAYOUT_CODE"
fi
# Try to ensure the kernel uses the new partitioning
# see https://github.com/rear/rear/issues/793
# First do a hardcoded sleep of 1 second so that
# the kernel and udev get a bit of time to process
# automated "read partition table changes" triggers
# of nowadays parted.
# Then to be backward compatible with traditional parted
# call partprobe explicitly to trigger the kernel
# to "read partition table changes" and if that fails
# wait 10 seconds before a first retry and if that fails
# wait 60 seconds before a final retry and if that fails
# ignore that failure and proceed "bona fide" because
# nowadays it should "just work" regardless of partprobe.
(
echo "sleep 1"
echo "if ! partprobe -s $device >&2 ; then"
echo " LogPrint 'retrying partprobe $device after 10 seconds' "
echo " sleep 10"
echo " if ! partprobe -s $device >&2 ; then"
echo " LogPrint 'retrying partprobe $device after 1 minute' "
echo " sleep 60"
echo " if ! partprobe -s $device >&2 ; then"
echo " LogPrint 'partprobe $device failed, proceeding bona fide' "
echo " fi"
echo " fi"
echo "fi"
) >> "$LAYOUT_CODE"
}
# vim: set et ts=4 sw=4: