/
131_include_filesystem_code.sh
308 lines (294 loc) · 16.7 KB
/
131_include_filesystem_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
# Code to recreate filesystems.
function create_fs () {
Log "Begin create_fs( $@ )"
local fs device mountpoint fstype uuid label options
device=${1#fs:}
read fs device mountpoint fstype uuid label options < <( grep "^fs.* $device " "$LAYOUT_FILE" )
label=${label#label=}
uuid=${uuid#uuid=}
# Wait until udev had created the disk partition device node before creating a filesystem there:
( echo "# Wait until udev had created '$device' before creating a filesystem there:"
echo "my_udevsettle"
) >> "$LAYOUT_CODE"
# If available try to use wipefs as a generic way to cleanup disk partitions
# and try to use dd as generic fallback to erase at least dos partition tables
# before creating a filesystem on a disk partition,
# see https://github.com/rear/rear/issues/540
# and https://github.com/rear/rear/issues/649#issuecomment-148725865
# and https://github.com/rear/rear/issues/1327
# and https://github.com/rear/rear/issues/799
# TODO: Enhancements welcome from whoever likes to maintain them ;-)
local cleanup_command="" cleanup_info_message=""
if has_binary wipefs ; then
# First try wipefs that supports '--force' in order to also erase the partition table on a block device.
# If that fails and regardless why it fails (i.e. play dumb), try a more conservative approach with 'wipefs --all'.
# If that also fails and regardless why it fails (play dumb), let dd erase the first 512 bytes as generic fallback.
# At https://github.com/rear/rear/wiki/Coding-Style see "Try to care about possible errors"
# and "Maintain backward compatibility" and "Dirty hacks welcome".
# Because the cleanup_command is added to the LAYOUT_CODE script (i.e. diskrestore.sh)
# and the LAYOUT_CODE script is run with 'set -e' have a final 'true' in order to
# not let "rear recover" abort only because cleanup of disk partitions failed:
cleanup_command="wipefs --all --force $device || wipefs --all $device || dd if=/dev/zero of=$device bs=512 count=1 || true"
cleanup_info_message="Using wipefs to cleanup '$device' before creating filesystem."
else
# As generic fallback use plain dd to erase dos partition tables
# on systems that do not have wipefs which should at least avoid
# issues like https://github.com/rear/rear/issues/1327 on all systems.
# Because the cleanup_command is added to the LAYOUT_CODE script (i.e. diskrestore.sh)
# and the LAYOUT_CODE script is run with 'set -e' have a final 'true' in order to
# not let "rear recover" abort only because cleanup of disk partitions failed:
cleanup_command="dd if=/dev/zero of=$device bs=512 count=1 || true"
cleanup_info_message="Using dd to cleanup the first 512 bytes on '$device' before creating filesystem."
fi
# Tell what will be done:
local create_filesystem_info_message="Creating filesystem of type '$fstype' with mount point '$mountpoint' on '$device'."
Debug "$create_filesystem_info_message"
echo "LogPrint '$create_filesystem_info_message'" >> "$LAYOUT_CODE"
Debug "$cleanup_info_message"
echo "# $cleanup_info_message" >> "$LAYOUT_CODE"
# Actually do it:
case "$fstype" in
(ext*)
# File system parameters:
local blocksize="" reserved_blocks="" max_mounts="" check_interval="" default_mount_options=""
local fragmentsize="" bytes_per_inode=""
local option name value
for option in $options ; do
name=${option%=*}
value=${option#*=}
case "$name" in
(blocksize)
blocksize=" -b $value"
;;
(fragmentsize)
fragmentsize=" -f $value"
;;
(bytes_per_inode)
bytes_per_inode=" -i $value"
;;
(reserved_blocks)
### reserved_blocks can be a number or a percentage.
if [[ ${value%\%} == ${value} ]] ; then
reserved_blocks=" -r $value"
else
reserved_blocks=" -m ${value%\%}"
fi
;;
(max_mounts)
max_mounts=" -c $value"
;;
(check_interval)
check_interval=" -i $value"
;;
(default_mount_options)
default_mount_options=" -o $value"
;;
esac
done
# Cleanup disk partition:
echo "$cleanup_command" >> "$LAYOUT_CODE"
# Use the right program to adjust tunable filesystem parameters on ext2/ext3/ext4 filesystems:
local tunefs="tune2fs"
# On RHEL 5, tune2fs does not work on ext4.
if [ "$fstype" = "ext4" ] && has_binary tune4fs ; then
tunefs="tune4fs"
fi
# Actually create the filesystem with initially correct UUID
# (addresses Fedora/systemd problem, see issue 851)
# "mkfs -U" works at least since SLE11 but it may fail on older systems
# e.g. on RHEL 5 mkfs does not support '-U' so that when "mkfs -U" fails
# we assume it failed because of missing support for '-U' and
# then we fall back to the old way before issue 851
# i.e. using "mkfs" without '-U' plus "tunefs -U":
if [ -n "$uuid" ] ; then
( echo "# Try 'mkfs -U' to create the filesystem with initially correct UUID"
echo "# but if that fails assume it failed because of missing support for '-U'"
echo "# (e.g. in RHEL 5 it fails, see https://github.com/rear/rear/issues/890)"
echo "# then fall back to using mkfs without '-U' plus 'tune2fs/tune4fs -U'"
echo "if ! mkfs -t ${fstype}${blocksize}${fragmentsize}${bytes_per_inode} -U $uuid -F $device >&2 ; then"
echo " mkfs -t ${fstype}${blocksize}${fragmentsize}${bytes_per_inode} -F $device >&2"
echo " $tunefs -U $uuid $device >&2"
echo "fi"
) >> "$LAYOUT_CODE"
else
echo "mkfs -t ${fstype}${blocksize}${fragmentsize}${bytes_per_inode} -F $device >&2" >> "$LAYOUT_CODE"
fi
# Adjust tunable filesystem parameters on ext2/ext3/ext4 filesystems:
# Set the label:
if [ -n "$label" ] ; then
echo "$tunefs -L $label $device >&2" >> "$LAYOUT_CODE"
fi
# Set the other tunable filesystem parameters:
tune2fsopts="${reserved_blocks}${max_mounts}${check_interval}${default_mount_options}"
if [ -n "$tune2fsopts" ] ; then
echo "$tunefs $tune2fsopts $device >&2" >> "$LAYOUT_CODE"
fi
;;
(xfs)
Log "Begin generating code to create XFS on $device ..."
# Cleanup disk partition:
echo "$cleanup_command" >> "$LAYOUT_CODE"
# Load xfs options from configuration files saved during
# 'rear mkbackup/mkrescue' by xfs_info.
# xfs info is called in 230_filesystem_layout.sh (layout/prepare)
# xfs_opts will be used as additional parameter for mkfs.xfs and
# ensures that xfs filesystem will be created exactly as original
# unless the user has explicitly specified XFS filesystem options:
local xfs_opts
local xfs_device_basename="$( basename $device )"
local xfs_info_filename="$LAYOUT_XFS_OPT_DIR/$xfs_device_basename.xfs"
# Only uppercase letters and digits are used to ensure mkfs_xfs_options_variable_name is a valid bash variable name
# even in case of complicated device nodes e.g. things like /dev/mapper/SIBM_2810XIV_78033E7012F-part3
# cf. current_orig_device_basename_alnum_uppercase in layout/prepare/default/300_map_disks.sh
local xfs_device_basename_alnum_uppercase="$( echo $xfs_device_basename | tr -d -c '[:alnum:]' | tr '[:lower:]' '[:upper:]' )"
# cf. predefined_input_variable_name in the function UserInput in lib/_input-output-functions.sh
local mkfs_xfs_options_variable_name="MKFS_XFS_OPTIONS_$xfs_device_basename_alnum_uppercase"
# Set which options to use for mkfs.xfs:
if test "${!mkfs_xfs_options_variable_name:-}" ; then
# When the user has specified device specific options for mkfs.xfs e.g. in MKFS_XFS_OPTIONS_SDA2 use that:
if test -s $xfs_info_filename ; then
LogPrint "Overriding $xfs_device_basename mkfs.xfs options in $xfs_info_filename with those in $mkfs_xfs_options_variable_name"
else
Log "Using $xfs_device_basename mkfs.xfs options in $mkfs_xfs_options_variable_name"
fi
xfs_opts="${!mkfs_xfs_options_variable_name:-}"
else
if test "$MKFS_XFS_OPTIONS" ; then
# When the user has specified global options for mkfs.xfs in MKFS_XFS_OPTIONS use that:
if test -s $xfs_info_filename ; then
LogPrint "Overriding $xfs_device_basename mkfs.xfs options in $xfs_info_filename with those in MKFS_XFS_OPTIONS"
else
Log "Using $xfs_device_basename mkfs.xfs options in MKFS_XFS_OPTIONS"
fi
xfs_opts="$MKFS_XFS_OPTIONS"
else
# When the user has not specified any options for mkfs.xfs
# recreate the XFS filesystem on that particular device as it originally was
# cf. https://github.com/rear/rear/issues/1998#issuecomment-445149675
# The function xfs_parse in lib/filesystems-functions.sh falls back to mkfs.xfs defaults
# (i.e. xfs_parse outputs nothing) when there is no $xfs_info_filename file where the
# XFS filesystem options of that particular device on the original system were saved:
Log "Parsing $xfs_device_basename mkfs.xfs options from $xfs_info_filename"
xfs_opts="$( xfs_parse $xfs_info_filename )"
fi
fi
# In case of fallback to mkfs.xfs defaults xfs_opts is empty:
contains_visible_char "$xfs_opts" && Log "Using $xfs_device_basename mkfs.xfs options: $xfs_opts" || LogPrint "Using $xfs_device_basename mkfs.xfs defaults"
# Decide if mkfs.xfs or xfs_admin will set uuid.
# Uuid set by xfs_admin will set incompatible flag on systems with
# enabled CRC. This might cause ReaR failure during grub installation.
# See: https://github.com/rear/rear/issues/1065
if [ -n "$uuid" ]; then
( echo "if ! mkfs.xfs -f -m uuid=$uuid $xfs_opts $device >&2; then"
echo " mkfs.xfs -f $xfs_opts $device >&2"
echo " xfs_admin -U $uuid $device >&2"
# xfs_admin -U might cause dirty structure and problems with
# mounting.
# xfs_repair will fix this.
echo " xfs_repair $device"
echo "fi"
) >> "$LAYOUT_CODE"
else
echo "mkfs.xfs -f $xfs_opts $device >&2" >> "$LAYOUT_CODE"
fi
# Set the label:
if [ -n "$label" ] ; then
echo "xfs_admin -L $label $device >&2" >> "$LAYOUT_CODE"
fi
Log "End of generating code to create XFS on $device"
;;
(reiserfs)
# Cleanup disk partition:
echo "$cleanup_command" >> "$LAYOUT_CODE"
# Actually create the filesystem:
echo "mkfs -t $fstype -q $device" >> "$LAYOUT_CODE"
# Set the label:
if [ -n "$label" ] ; then
echo "reiserfstune --label $label $device >&2" >> "$LAYOUT_CODE"
fi
# Set the UUID:
if [ -n "$uuid" ] ; then
echo "reiserfstune --uuid $uuid $device >&2" >> "$LAYOUT_CODE"
fi
;;
(btrfs)
# Cleanup disk partition provided the disk partition is not already mounted:
echo "mount | grep -q $device || $cleanup_command" >> "$LAYOUT_CODE"
# Actually create the filesystem provided the disk partition is not already mounted.
( echo "# if $device is already mounted, skip"
echo "# force overwriting existing btrfs when the disk was already used before"
echo "if ! mount | grep -q $device >&2 ; then"
) >> "$LAYOUT_CODE"
if [ -n "$uuid" ] ; then
# Latest version of btrfs provides -U option to specify UUID druring the filesystem creation.
# User -f [force] to force overwriting an existing btrfs on that disk partition
# when the disk was already used before, see https://bugzilla.novell.com/show_bug.cgi?id=878870
( echo " # Try to create btrfs with UUID"
echo " if ! mkfs -t $fstype -U $uuid -f $device >&2 ; then"
# Problem with old btrfs version is that UUID cannot be set during mkfs! So, we must map it and
# change later the /etc/fstab, /boot/grub/menu.lst, etc.
echo " mkfs -t $fstype -f $device >&2"
echo " new_uuid=\$( btrfs filesystem show $device 2>/dev/null | grep -o 'uuid: .*' | cut -d ':' -f 2 | tr -d '[:space:]' )"
echo " if [ $uuid != \$new_uuid ] ; then"
echo " # The following grep command intentionally also"
echo " # fails when there is not yet a FS_UUID_MAP file"
echo " # and then the FS_UUID_MAP file will be created:"
echo " if ! grep -q $uuid \"$FS_UUID_MAP\" ; then"
echo " echo \"$uuid \$new_uuid $device\" >> $FS_UUID_MAP"
echo " else"
echo " # Required when we restart rear recover (via menu) - UUID changed again."
echo " old_uuid=\$(grep ${uuid} $FS_UUID_MAP | tail -1 | awk '{print \$2}')"
echo " SED_SCRIPT=\";/${uuid}/s/\${old_uuid}/\${new_uuid}/g\""
echo " sed -i \"\$SED_SCRIPT\" \"$FS_UUID_MAP\""
echo " fi"
echo " fi # end of [ $uuid != $new_uuid ]"
echo " fi"
) >> "$LAYOUT_CODE"
else
# UUID is not provided. Create FS without UUID
# Latest version of btrfs provides -U option to specify UUID druring the filesystem creation.
echo " mkfs -t $fstype -f $device" >> "$LAYOUT_CODE"
fi
# Set the label:
if [ -n "$label" ] ; then
echo " btrfs filesystem label $device $label >&2" >> "$LAYOUT_CODE"
fi
echo "fi" >> "$LAYOUT_CODE"
;;
(vfat)
# Cleanup disk partition:
echo "$cleanup_command" >> "$LAYOUT_CODE"
# Actually create the filesystem with or without label:
if [ -n "$label" ] ; then
# we substituted all " " with "\\b" in savelayout (\\b becomes \b by reading label)
echo "$label" | grep -q '\b'
if [ $? -eq 0 ] ; then
label2="$(echo $label | sed -e 's/\\b/ /g')" # replace \b with a " "
label="$label2"
fi
echo "mkfs.vfat -n \"$label\" $device" >> "$LAYOUT_CODE"
else
echo "mkfs.vfat $device" >> "$LAYOUT_CODE"
fi
# Set the UUID:
if [ -n "$uuid" ]; then
# The UUID label of vfat is changed by recreating the fs, we must swap it.
cat >> "$LAYOUT_CODE" <<EOF
new_uuid=\$(blkid_uuid_of_device $device)
if [ "$uuid" != "\$new_uuid" ] ; then
echo "$uuid \$new_uuid $device" >> "$FS_UUID_MAP"
fi
EOF
fi
;;
(*)
# Cleanup disk partition:
echo "$cleanup_command" >> "$LAYOUT_CODE"
# Actually create the filesystem:
echo "mkfs -t $fstype $device >&2" >> "$LAYOUT_CODE"
;;
esac
# Call the mount_fs function (in 133_include_mount_filesystem_code.sh) with argument $1 (device):
mount_fs ${1}
Log "End create_fs( $@ )"
}