#!/bin/sh # Author: Didier Spaier, Paris, France # Last edited on 21 January 2020 # This script enlarges the last partition of a device so that it uses all # the previously free space on this device after this partition. # Variables used: # 'root' is the name of the root partition, prefixed by /dev/. # 'rootname' is the name of the root partition, not prefixed . # 'rootdevname' is the name of the device to which the root # partition belongs, not prefixed. # 'lastname' is the name of the last partition, prefixed by /dev/. # 'lastnumber' is the number of this partition. # 'laststart' is the first sector of this partition. # 'lastend' is the last sector of this partition. # 'stripname' is the name of the last partition, not prefixed. # 'freespace' is the free space after the last partition. # 'fstype is the type of the file system in the last partition. # 'espname' is the name of the ESP mounted on /boot/efi, not prefixed. # 'esptype' is the GUID of this ESP. # 'espfstype" is the file system type of this ESP. # 'espdevname" is the name of the device to which this ESP belongs, not # prefixed. # This script handles file system of types ext2 ext3 and ext4 for # the last partition, else output a warning and exit. # If there is not enough free space after the last partition to # enlarge it with a good alignment it outputs a warning and exit. # This script handles only devices with a gpt, else exit. # TODO: support f2fs and allow the user to set the size of /. export TEXTDOMAIN=slint . gettext.sh if [ ! $(id -u) -eq 0 ];then gettext "This script should be executed by root." echo exit 1 fi root=$(cat /proc/mounts | grep "/ "|cut -d" " -f 1) rootname=$(echo $root|sed "s,/dev/,,") rootdevname=$(lsblk -lo PKNAME,NAME|grep $rootname|cut -d" " -f 1) gpt=$(parted -s /dev/$rootdevname print 2>/dev/null|grep artition|grep gpt) if [ "$gpt" = "" ];then echo "This script can only handle devices with a gpt, sorry." exit fi # Move the backup GPT data structures to the end of the disk sgdisk -e /dev/$rootdevname 2>/tmp/enlargelastpart.log 1>/dev/null lastnumber=$(partx -s /dev/$rootdevname|tail -n 1|cut -d" " -f 2) laststart=$(partx -s /dev/$rootdevname|tail -n 1|cut -d" " -f 3) lastend=$(partx -s /dev/$rootdevname|tail -n 1|cut -d" " -f 4) lastname=$(fdisk -l /dev/$rootdevname|tail -n 1|cut -d" " -f 1) stripname=$(echo $lastname|sed "s,/dev/,,") endfree=$(sgdisk -E /dev/$rootdevname 2>>/tmp/enlargelastpart.log) fstype="$(blkid | grep $lastname| sed 's/.*TYPE="//;s/".*//')" if [ "$(echo $fstype|grep ext)" = "" ]; then eval_gettext "File system type \$fstype is not(yet?) supported, sorry." echo exit fi freespace=$((${endfree}-${lastend})) # The test below also prevents to use a free space before the # partition as then $freespace would have a negative value. If # there is enough free space to enlarge the last partition after # it, but there is more free space before it, the test below # prevents to enlarge the partition. Le me know if handling this case # is a must have for you and why. if [ $freespace -lt 2049 ]; then eval_gettext "Not enough free space to enlarge \$lastname, sorry." echo exit fi eval_gettext "Enlarging the partition \$lastname to \$freespace sectors..." echo # Delete the last partition sgdisk -d $lastnumber /dev/$rootdevname 2>>/tmp/enlargelastpart.log 1>/dev/null # Then recreate it bigger but starting at the same place sgdisk -n ${lastnumber}:${laststart}:${endfree} /dev/$rootdevname 2>>/tmp/enlargelastpart.log 1>/dev/null # Inform the kernel of partition table changes partprobe /dev/$rootdevname eval_gettext "The partition \$lastname has been enlarged." echo eval_gettext "Enlarging the file system in \${lastname}..." echo resize2fs $lastname 2>>/tmp/enlargelastpart.log 1>/dev/null eval_gettext "The filesystem in \$lastname now encompasses the full partition." echo gettext "Building an initrd..." echo sh /usr/share/mkinitrd/mkinitrd_command_generator.sh |sh 2>>/tmp/enlargelastpart.log 1>/dev/null gettext "The initrd has been built and installed." # Install grub in the MBR of this drive. We don't want to fiddle with other # devices. However even if /boot/efi is in another device we will still # install the grub EFI boot manager in it. echo echo eval_gettext "(re)installing the GRUB bootloader in /dev/\$rootdevname is necessary unless this system boots from another drive." echo echo eval_gettext "(re)install GRUB in /dev/\$rootdevname? [Y/n] " read answer if [ "$answer" = "n" ] || [ "$answer" = "n" ]; then exit fi check_efi() { espdevname="" # We will install grub for UEFI booting if and only if: # 1. A partition is mounted on /boot/efi. # 2. It is EFI System Partition according to its UUID. # 3. It contains a FAT file system. # If all these conditions are met, we will install grub in this ESP. # If /boot/efi is not listed /etc.fstab, bail out. if [ "$(cat /etc/fstab|grep /boot/efi)" = "" ]; then return fi # Mount /boot/efi if not done if [ "$(cat /proc/mounts|grep /boot/efi)" = "" ]; then mount /boot/efi fi espname=$(lsblk -l -o name,mountpoint |grep /boot/efi|cut -d" " -f 1) if [ "$espname" = "" ]; then return fi # If the partition mounted as /boot/efi is not an ESP, bail out. # The UEFI specification states that an ESP has this GUID; # C12A7328-F81F-11D2-BA4B-00A0C93EC93B in case of a GPT layout. ESPPARTTYPE=C12A7328-F81F-11D2-BA4B-00A0C93EC93B esptype=$(fdisk -lo type-uuid,device /dev/$rootdevname|grep $espname|cut -d" " -f1) if [ ! "$esptype" = "ESPPARTTYPE" ]; then return fi # If the file system of the partition mounted as /efi/boot is not # VFAT, bail out. espfstype="$(blkid | grep $espname| sed 's/.*TYPE="//;s/".*//')" if [ "(echo $espfstype| grep -i vfat)" = "" ]; then return fi # All test passed we need to know the name of the device that hosts # the EFI partition. It is the pkname field of lsblk. espdevname=$(lsblk -l -o pkname,name|grep $espname|cut -d" " -f 1) } check_efi echo echo gettext "You might need extra parameters to be included in the boot command line of the installed system. If you typed parameters before booting the Slint installer, you will probably want to enter the same ones here. If you don't need any extra parameter to be included, just press ENTER to continue. Include 'rootdelay=10' (without the quotes) for an USB attached drive. You may replace 10 by another number of seconds." echo echo gettext "Type extra parameters or press Enter: " read answer echo DEFAULT="ro $answer" sed -i "s/#*GRUB_CMDLINE_LINUX_DEFAULT.*/GRUB_CMDLINE_LINUX_DEFAULT=\"$DEFAULT\"/" /etc/default/grub if [ ! "espdevname" = "" ]; then eval_gettext "Installation in EFI mode in /usr/lib64/grub/x86_64-efi on /dev/\$espname" echo # If the machine is running in EFI mode, propose to install a boot # entry for Slint in the firmware's boot menu EFIMENUENTRY=n if [ -d /sys/firmware/efi ] && [ ! "(lsblk -lo fstype|grep [[:alpha:]])" = "" ]; then echo gettext "Do you want to install a boot entry for Slint in the EFI firmware menu? " EFIMENUENTRY=y read -p "[n/Y] " EFIMENENUTRY fi echo if [ "$EFIMENUENTRY" = "y" ] || [ "EFIMENURENTRY" = "Y" ]; then grub-install --target=x86_64-efi --bootloader-id=slint /dev/$espdevname else grub-install --no-nvram --target=x86_64-efi --bootloader-id=slint /dev/$espdevname fi mkdir -p /boot/efi/EFI/BOOT if [ -f /boot/efi/EFI/slint/grubx64.efi ]; then if [ ! -f /boot/efi/EFI/BOOT/BOOTx64.EFI ]; then cp /boot/efi/EFI/slint/grubx64.efi /boot/efi/EFI/BOOT/BOOTx64.EFI else echo "EFI\slint\grubx64" > /boot/efi/startup.nsh fi fi fi echo eval_gettext "Installation on the MBR of /dev/\$rootdevname" echo grub-install --recheck --target=i386-pc /dev/$rootdevname sleep 2 # Update the boot menu echo gettext "Updating boot/grub/grub.cfg..." echo update-grub sleep 2 echo eval_gettext "grub has been installed in /dev/\$rootdevname. If a bootloader was already installed in the MBR of another device, you may need to reconfigure it." echo