Automating partitioning setup of /dev/sda on /dev/sdc

Objective: To recreate the partitioning setup of /dev/sda on /dev/sdc

How would I parse the below information and initialize variables
(an array?) that can be used to build sgdisk commands in a script, regardless of the number of partitions?

Something along the lines of:

sgdisk -n $partnum:$startsec:$endsec -t $partnum:$parttype -c $partnum:$name /dev/sdc

for each partition listed in text produced by an sgdisk - i command.

I am thinking that I can save this text to a file in the backup process and then use it in the restoration process...

Thank you vey much in advance for any time and effort expended in answering my
question! :slight_smile:

root@redbrick /: sgdisk -p /dev/sda
Disk /dev/sda: 1465149168 sectors, 698.6 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 3A4C6201-749A-4B13-93E0-A94B52349823
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 1465149134
Partitions will be aligned on 2048-sector boundaries
Total free space is 749229 sectors (365.8 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048          411647   200.0 MiB   EF00  EFI System Partition
   2          411648         1435647   500.0 MiB   8300  
   3         1435648      1464401919   697.6 GiB   8300

As this is crucial (and possibly dangerous, e.g. disk structures differ), and as it's a one off exercise, I'd do it manually and not by script/automated parsing.

I agree. This is for a home project on expendable resources. This is part of a Crashed Disk Recovery project that I am working on. Lots of hard disks here to experiment with!

---------- Post updated at 12:15 PM ---------- Previous update was at 12:13 PM ----------

Can you help with the scripting?

Please don't bump posts.

It would take a great deal of trial and error to get what you want. I'm not sure sgdisk -p is printing all the info you really need, and there's often more to it than just plugging in the right numbers.

I take it your goal is to reorganize partitions into some known-good configuration? have you considered dd?

What exactly is your "crashed disk recovery project"?

Yes DD will not work because the cylinders value on the other drive is not the same as the originating drive. so my only approach would be to recreate the partitions manually that match the original drive, format them out, and then replace the file structure in each one of those partitions. In this case it's a single partition for EFI, one for Boot and a LUKS partition... Any other method seems to result in a corrupted partition table.

sgdisk is providing just enough info to recreate the partition structure. I'm just not sure how to pull that info and what "for" loops I would need.

Just how old are these hard drives? "cylinders" is completely meaningless on any drive newer than 1996, and a partition table with primary partition starting at sector 2048 looks pretty modern too.

Having not seen what you were doing, I can't say why your other methods resulted in a corrupted partition table.

The first time I used the DD to copy the first 2048 sectors off the drive and then I used dd to also copy both of the other partitions. At that point gdisk would complain that I had a corrupt GPT table and that my partition was over running X number of sectors into the next partition. I read somewhere that that's because the way that the drive handles writing the information to the disc is based upon the geometry of the cylinders heads and sectors ...

---------- Post updated at 02:22 PM ---------- Previous update was at 02:19 PM ----------

That's why I decided trying to copy the partition information over to another drive was not a good idea and that what I should actually do is just go ahead and zap a disc get a brand new GPT on there and then format it out one partition at a time and then copy the data into it

That's incorrect, cylinders and sectors haven't mattered since 1996. The computer just asks for block 6, block 123485701, or whatever, and the hard drive handles all the rest.

What do you mean by "first 2048 sectors"? Do you mean blocks?

I see a couple of pitfalls here. First of all, did you reload the partition table after running dd? Linux needs to be told "the partition table has changed" when you do that, or it will just keep using the old layout until the next reboot. There's also a "backup" GPT sector which might have to be regenerated after you do the copy.

1 Like

I'm out on the road right now I'll get back to my house and then I'll be able to respond thank you

---------- Post updated at 03:25 PM ---------- Previous update was at 02:25 PM ----------

This is the piece preceding the partitioning in the recovery script...
All drive designations are for the 2nd external USB Drive -- which gets attached as /dev/sdc.
The USB drive used for the backup process is /dev/sdb. /dev/sdb1 is a LiveCD partition and /dev/sdb2 is the data partition.

#!/bin/bash
#
# This scipt is to be run from a LiveCD environment in a root terminal
#
clear
echo
echo
echo "Mounting USB Hard Drive to mount point /mnt/USBDrive..."
# We'll create a mount point and mount the main directory structure of our backup drive to this point.
mkdir -p /mnt/USBDrive
mount -o defaults /dev/sdb2 /mnt/USBDrive
echo "Done!"
echo 
# We are going to need the physical volume name and UUID along with the Volume Group name later in this process
# We also want to determine the starting and ending sector (along with the partition number) of our luks partition
echo "Setting a few variables for later..."
pvname=$(grep Name /mnt/USBDrive/lvminfo/pvparse | cut -d'/' -f4)
pvuuid=$(grep UUID /mnt/USBDrive/lvminfo/pvparse | cut -b 25-62)
vgname=$(grep ^/dev /mnt/USBDrive/lvminfo/fstab_info | cut -d'/' -f4 | cut -d'-' -f1 | sed '2,99d')

This is the section following the partitioning piece...

# We need to inform the kernel about the changes
partprobe
# And format the partition we just created
mkfs -t ext4 /dev/sdc$partnum
echo
echo "Restoring Cryptsetup header and key slots..."
# This command always gives an error that can be disregarded. Thus, the redirection of stderr to null
cryptsetup luksHeaderRestore /dev/sdc$partnum --header-backup-file /mnt/USBDrive/lvminfo/cryptbackup.img 2>/dev/null
echo
echo "Opening crypt partition for writing..."
cryptsetup -vv open /dev/sdc$partnum --type luks $pvname
echo
echo "Restoring Physical Volume..."
# This command always gives an error that can be disregarded. Thus, the redirection of stderr to null
pvcreate -f --uuid $pvuuid --restorefile /mnt/USBDrive/lvminfo/$vgname /dev/mapper/$pvname 2>/dev/null
echo
echo "Restoring & Checking Volume Group and Logical Volumes structures..."
vgcfgrestore $vgname
lvs -a -o +devices
vgchange -ay $vgname
pvck -vv
vgck -vv
mkfs -t ext4 /dev/mapper/$vgname-*
mkswap /dev/mapper/$vgname-swap
echo
echo "Creating Mount Points, mounting individual LVM's from Volume Group and restoring data..."
for fs in ${farry[@]}
do
    mkdir -p /mnt/$vgname/$fs
    mount /dev/mapper/${vgname}-$fs /mnt/$vgname/$fs
    rsync -aHvu /mnt/USBDrive/Recover/$fs /mnt/$vgname/$fs
done
rsync -aHvu --ignore-existing /mnt/USBDrive/Recover/ /mnt/$vgname/
mv -f /mnt/USBDrive/lvminfo/cryptbackup.img /mnt/USBDrive/lvminfo/cryptbackup.img.bak
exec $SHELL

This is what i DID have until I realized that I kept getting a corrupted partition table.

startsec=$(grep ^/dev /mnt/USBDrive/info/fdisk_info | grep G | cut -d" " -f3)
endsect=$(grep ^/dev /mnt/USBDrive/info/fdisk_info | grep G | cut -d" " -f4)
partnum=$(grep $startsec /mnt/USBDrive/info/sgdisk_info | cut -b4)
# The following line initializes an array of variables from a list of lvnames created from fstab_info
read -a farry <<< $(grep $vgname /mnt/USBDrive/lvminfo/fstab_info | cut -d'-' -f2 | cut -d'/' -f1 | cut -d" " -f1 | awk '{printf("%s%s",$0,NR%9?" ":"\n")}')
# Once we have gotten the volume group name from fstab we can create a mount point for the restore process 
mkdir -p /mnt/$vgname
echo
# We start the recovery process by writing our saved critical disk areas to the new drive
# This will give us a mountable drive with the partition table, EFI and boot partitions as they were on the original drive
# sgdisk /dev/sda --backup=/mnt/USBDrive/info/sgdisksda
# sgdisk  /dev/sdc --load-backup= /mnt/USBDrive/info/sgdisksda
echo "Restoring the first 2048 sectors of /dev/sda..."
dd if=/mnt/USBDrive/dd/partition-restore of=/dev/sdc bs=1 count=2047
echo
echo "Restoring the EFI partition as /dev/sda1..."
dd if=/mnt/USBDrive/dd/sda1EFI-restore of=/dev/sdc1 bs=8192
echo
echo "Restoring the Boot partition as /dev/sda2..."
dd if=/mnt/USBDrive/dd/sda2Boot-restore of=/dev/sdc2 bs=8192
echo
echo "Prepping to restore the luks partition, and VG/LVM structures..."
echo
# Just to ensure that there isn't any old luks data on our new drive that will present errors during the restortion of our saved luks partition header image, we need to wipe out any signs of any previous lvm info that might be there
echo "First we will ensure that no old crypt/lvm info remains on our recovery disk. If there is the restoration will error out."
cryptsetup -v isLuks /dev/sdc$partnum
head -c 3145728 /dev/zero > /dev/sdc$partnum; sync
# Next, we will recreate the partition from scratch and format it to ext4
echo "Then we will create a new /dev/sda3 and restore our backup img"
sgdisk -d $partnum -n $partnum:$startsec:$endsec -t $partnum:8300 /dev/sdc

(As you can see, in the beginning, to work around the corrupt partition issue,
I was trying to simply delete /dev/sdc3, put in a new partition, format it, run partprobe to update the kernel
and then do the cryptsetup luksRestore.
But I kept getting a "partition corrupt' error and exit.)
Which is what brings me to my original question....
How can I parse and initialize an array and a for loop that will just recreate these partitions from scratch rather than doing it otherwise. :slight_smile:

Since all information gathered about /dev/sda showed that the EFI partition started at sector 2048,
I just used dd to copy sectors 0-2047 and then restored the other two partitions using the same method.

All of the information that I thought I might need to do the recovery part was saved during the execution of the backup script:

#!/bin/bash
mkdir -p /mnt/USBDrive
echo "Mounting USB Hard Drive..."
mount -o defaults /dev/sdb2 /mnt/USBDrive
echo "Done!"
echo
mkdir -p /mnt/USBDrive/dd
echo "Backing up first 2048 sectors of /dev/sda to /mnt/USBDrive/dd"
dd if=/dev/sda of=/mnt/USBDrive/dd/partition-restore bs=1 count=2047
echo
echo "Backing up the EFI partition to /mnt/USBDrive/dd "
dd if=/dev/sda1 of=/mnt/USBDrive/dd/sda1EFI-restore bs=8192
echo
echo "Backing up the Boot partition to /mnt/USBDrive/dd "
dd if=/dev/sda2 of=/mnt/USBDrive/dd/sda2Boot-restore bs=8192
echo
mkdir -p /mnt/USBDrive/info
echo "Backing up critical hardware information to  /mnt/USBDrive/info"
lspci -vv > /mnt/USBDrive/info/lspci_info
lshw > /mnt/USBDrive/info/lshw_info
hdparm -I /dev/sda > /mnt/USBDrive/info/hdparm_info
blkid > /mnt/USBDrive/info/blkid_info
fdisk -l /dev/sda > /mnt/USBDrive/info/fdisk_info
sgdisk -p /dev/sda > /mnt/USBDrive/info/sgdisk_info
smartctl -d ata -a -i /dev/sda > /mnt/USBDrive/info/smartctl_info
df -h > /mnt/USBDrive/info/df_info
echo
echo "Backing up critical LVM info to /mnt/USBDrive/lvminfo" 
mkdir -p /mnt/USBDrive/lvminfo
# sgdisk backup
# -b or --backup     filename     Save a backup of the disk to the specified file.
pvdisplay > /mnt/USBDrive/lvminfo/pvdisplay
vgdisplay > /mnt/USBDrive/lvminfo/vgdisplay
lvscan > /mnt/USBDrive/lvminfo/lvscan
lvdisplay > /mnt/USBDrive/lvminfo/lvdisplay
lvmdiskscan > /mnt/USBDrive/lvminfo/lvmdiskscan
lvs -a -o +devices > /mnt/USBDrive/lvminfo/lvscmd
echo
echo "Backing up cryptsetup info to /mnt/USBDrive/lvminfo"
cryptsetup -q luksHeaderBackup /dev/sda3 --header-backup-file /mnt/USBDrive/lvminfo/cryptbackup.img
echo
echo "Backing up LVM Structure to  /mnt/USBDrive/lvminfo "
vgcfgbackup
vgcfgbackup -f /mnt/USBDrive/lvminfo/fedora fedora
vgdisplay --verbose | grep PV > /mnt/USBDrive/lvminfo/pvparse
echo
echo "Backing up crypttab and fstab to /mnt/USBDrive/lvminfo"
cat /etc/crypttab > /mnt/USBDrive/lvminfo/crypttab_info
cat /etc/fstab > /mnt/USBDrive/lvminfo/fstab_info
echo
echo "Running full system backup: Backing up to /mnt/USBDrive/Recover"
mkdir -p /mnt/USBDrive/Recover
echo
rsync -aHvu --delete --exclude={/backup/*,/dev/*,/proc/*,/sys/*,/run/*,/mnt/*,/media/*,/lost+found,/home/*/.thumbnails/*,/home/*/.local/share/Trash/*,/home/*/.gvfs/*,/home/*/.cache/google/*,/home/*/.cache/mozilla/*} /* /mnt/USBDrive/Recover
echo
echo
# Add in prompt to either unmount or leave mounted. umount /mnt/USBDrive
exec $SHELL

But WAIT!! Something just hit me!!

echo "Backing up first 2048 sectors of /dev/sda to /mnt/USBDrive/dd"
dd if=/dev/sda of=/mnt/USBDrive/dd/partition-restore bs=1 count=2047

actually gives me 2048 BLOCKS and not 2047 sectors, right?!?! Am I on the right track here???

---------- Post updated at 03:58 PM ---------- Previous update was at 03:25 PM ----------

So if I understand it correctly, in order to back up everything on the disk prior to the first partition (which starts at sector 2048) I would actually have to use a bs of 512 and indicate a count of 2047. Correct?

dd if=/dev/sda of=/mnt/USBDrive/dd/partition-restore bs=512 count=2047

Since the sector size is 512 bytes, that should give me the equivalent of the first 2047 sectors, correct?

dd if=/dev/sda of=/mnt/USBDrive/dd/partition-restore bs=1 count=2047 will give you 2047 bytes, not blocks, because you have set the block size to 1. Use bs=512, or just leave out bs entirely, since dd will assume 512 when you don't tell it otherwise. I think you want 2048, not 2047, as well.

There is no 'sector', 'cylinder', 'head', 'track', etc, etc, etc. None of that has been relevant for going on 20 years. Hard drives do have a block size though, of 512 bytes (and even the very newest drives, which use 4K blocks internally, still act like they have 512 byte blocks.)

34612341692783461 lines of script aren't going to help you when you don't know how to do it by hand.

1 Like

Ok. How do I mark this thread closed?

I'm not familiar with sgdisk and wouldn't know how to construct commands for it. To extract the desired values form above mentioned output, try

sgdisk -p /dev/sda |
while read partnum startsec endsec size unit parttype name
   do [[ $partnum =~ [[:digit:]]{1,2} ]] &&
        echo $partnum $startsec $endsec $size $parttype $name
   done
1 2048 411647 200.0 EF00 EFI System Partition
2 411648 1435647 500.0 8300
3 1435648 1464401919 697.6 8300

You'd need to assign the values to e.g. an array in lieu of the echo, then.

Thank you