­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ # 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 junk local blocksize layout dasdtype dasdcyls junk2 read component disk size label junk < <(grep "^disk $1 " "$LAYOUT_FILE") ### Disks should be block devices. [[ -b "$disk" ]] BugIfError "Disk $disk is not a block device." ### Find out the actual disk size. local disk_size=$( get_disk_size $(get_sysfs_name "$disk") ) [[ "$disk_size" ]] BugIfError "Could not determine size of disk $disk, please file a bug." [[ $disk_size -gt 0 ]] StopIfError "Disk $disk has size $disk_size, unable to continue." cat >> "$LAYOUT_CODE" </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 # $junk can contain useful DASD-specific fields create_partitions "$disk" "$label" "$junk" cat >> "$LAYOUT_CODE" <> "$LAYOUT_CODE" < $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" <> "$LAYOUT_CODE" < 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" <&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 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: