[svlug] How to back up my son's GPT? [sort of solved]

Steve Litt slitt at troubleshooters.com
Thu Nov 27 22:07:15 PST 2014


On Thu, 27 Nov 2014 16:40:47 -0800
Scott DuBois <sdubois at linux.com> wrote:

> On 11/27/2014 11:23 AM, Steve Litt wrote:
> > This is actually more of a Linux question than a Windows one,
> > because you're using System Rescue CD to back up your GPT. Also,
> > whether you have Windows, Linux, BSD or emacs, you need to back up
> > your GPT for bare metal restoration, and to back it up, you need to
> > know how big it is.
> 
> The Win built-in tool doesn't do this for their systems? I thought
> they had a tool for this?

Hi Scott,

I'm not very good at Windows, and besides, I don't trust it. So I wrote
this program that appears to study the disk, figure out its blocksize
by trial and error, and print out the dd commands to back up both copies
of the GPT. Right now it's very noisy because I'm not at all confident
of it. I have a very hard time with picket fence conditions. The picket
fence thing is also why I added 10 bytes to the buffer: sloppy, but
easier to waste 10 bytes than risk segfaults because of a picket fence
condition.

Its results seem to agree with gdisk (which unfortunately isn't on
System Rescue CD, or this could have been a 20 line shellscript), so
that's a good sign. 

The program appears below. I'm going to test it a little more, then
compile it static so I can use it within System Rescue CD by loading it
with a thumb drive.


=============================================================
/*
 * gpt_info.c: calculate dd commands
 *       to back up both copies of a gpt
 * Copyright (C) 2014 by Steve Litt
 * Licensed by the GNU GPL version 2.0. See the COPYING file.
 * Version 0.1 infra-alpha
 */
#include <stdio.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>

struct gpt_info {
	char signature[8];
	uint8_t revision[4];
	uint32_t header_size;
	uint8_t header_crc32[4];
	uint8_t reserved0a[4];        /* always 0's */
	uint64_t current_lba;
	uint64_t backup_lba;
	uint64_t first_useable_lba;
	uint64_t last_useable_lba;
	char guid[16];
	uint64_t part_array_start;   /* always 2 on primary GPT */
	uint32_t number_of_partitions;
	uint32_t partition_entry_size;  /* usually 128 */
	uint8_t partition_array_crc32[3];
	uint8_t reserved0b[420]; /* Bigger w blocksize > 512 */
};

unsigned get_partition_size(const char * path){
	struct statvfs statvfsbuf;
	statvfs(path, &statvfsbuf);
	return((int)statvfsbuf.f_bsize);
}

char * allocate_read_area(unsigned blocksize){
	char * buf = (char *) malloc(blocksize + 10);
	assert(buf != NULL);
	return(buf);
}

struct gpt_info * get_primary_gpt(
		const char *device,
		char *buf,
		unsigned blocksize
		){

	/**** OPEN DEVICE FILE (LIKE /dev/sda) FOR READ ****/
	int dev_as_file = open(device, O_RDONLY, 0); 
	if(dev_as_file < 3){
		printf("ERROR: open device path returns=>%d<, ",
				dev_as_file);
		printf("aborting!\n");
		perror("Open Error is"); 
		free(buf);
		exit(1);
	}

	/**** SKIP THE MBR ****/
	if(read(dev_as_file, buf, blocksize) < blocksize){
		printf("Failed reading MBR\n");
		exit(1);
	}

	/**** GRAB THE PRIMARY GPT ****/
	if(read(dev_as_file, buf, blocksize) < blocksize){
		printf("Failed reading GPT header.\n");
		exit(1);
	}

	close(dev_as_file);
	struct gpt_info *gpt =  (struct gpt_info *) buf;
	return(gpt);
}



int main(int argc, char * argv[]){
	const char * device = argv[1];
	struct gpt_info *gpt=NULL;
	char *buf=NULL;

	/**** DEDUCE BLOCKSIZE AND GET GPT IF POSSIBLE ****/
	unsigned blocksize = 512;
	int highest_blocksize_to_try = 8192;
	while(1){
		if(blocksize <= highest_blocksize_to_try)
			printf("Trying blocksize %d.\n", blocksize);
		buf = allocate_read_area(blocksize + 10);
		gpt = get_primary_gpt(device, buf, blocksize);
		if(!strncmp(gpt->signature, "EFI PART", 3))
			break; /* Got valid gpt */
		if (blocksize > highest_blocksize_to_try)
			break; /* No gpt found */
		blocksize += 512;
		free(buf);
		buf=NULL;
		gpt=NULL;
	}
	if(blocksize > highest_blocksize_to_try){
		printf("\nDevice %s appears to have no gpt, ",
				device);
		printf("aborting.\n\n");
		free(buf);
		exit(1);
	}

	/**** IF YOU GOT THIS FAR, THERE'S A VALID ****/
	/**** PRIMARY GPT WITH CORRECT BLOCKSIZE ****/

	/**** GET INFO FOR SECONDARY GPT ****/

	/**** RECITE THE INFORMATION ****/
	printf("Buf=>%s<\n", buf);
	printf("Block size is %d.\n", blocksize);
	printf("Signature =>%s<\n", gpt->signature);
	printf("Current LBA =>%llu<\n",
			(long long unsigned) gpt->current_lba);
	printf("First useable LBA =>%llu<\n",
			(long long unsigned) gpt->first_useable_lba);
	printf("Last  useable LBA =>%llu<\n",
			(long long unsigned) gpt->last_useable_lba);
	printf("Secondary GPT header LBA =>%llu<\n",
			(long long unsigned) gpt->backup_lba);

	/**** HANDLE SECONDARY GPT, NEEDED ONLY FOR REDUNDANCY ****/
	/**** PUT SECONDARY GPT READ HERE IF LATER NEEDED ****/

	/**** PRINT THE COMMANDS ****/
	/**** REMEMBER, BACKING UP MBR *PLUS* PRIMARY GPT ****/
	printf("\nCommand to back up main GPT is:\n");
	printf("dd if=%s of=primaryy.bup bs=%u count=%llu\n",
			device,
			blocksize,
			(long long unsigned)gpt->first_useable_lba);

	printf("\nCommand to back up secondary GPT is:\n");
	printf("dd if=%s of=secondaryy.bup bs=%u ",
		device,
		blocksize);

	printf("count=%llu skip=%llu\n",
		(long long unsigned)
			(gpt->backup_lba - gpt->last_useable_lba),
		(long long unsigned)gpt->last_useable_lba);

	/**** SHUT DOWN THE PROGRAM ****/
	free(buf);
	return(0);
}
=============================================================

SteveT

Steve Litt                *  http://www.troubleshooters.com/
Troubleshooting Training  *  Human Performance




More information about the svlug mailing list