Example #1
0
/*****************************************************************
Start here
*****************************************************************/
int main(int np, char **p)
{
	char		src_drive[NAME_LENGTH] = "/dev/hda", /* source drive */
			dst_drive[NAME_LENGTH] = "/dev/hdb"; /* destination drive */
	int		help = 0, /* set to true to indicate problem with command line */
			ask_for_partitions = 1,	/* default is true; set to false if partitions given on command line */
			status, /* error return on I/O operations */
			i; /* loop index */
	static disk_control_block *src_disk,*dst_disk;
	static off_t	lba = 0, /* a sector LBA address usually found as a loop index */
			common, /* number of sectors common to source & destination */
			diffs = 0, /* count of sectors that don't match */
			src_lba, /* address of current sector on source */
			dst_lba,  /* address of current sector on destination */
			byte_diffs = 0, /* count of bytes that differ between src and dst */
			match = 0, /* number of matching sectors */
			/* zero .. other apply to dst sectors beyond common area */
			zero = 0, /* number of zero filled sectors */
			sfill = 0, /* number of sectors filled with src fill char */
			dfill = 0, /* number of sectors filled with dst fill char */
			ofill = 0, /* number of sectors filled with some other fill char */
			other = 0; /* number of remaining (unfilled) sectors */
	static unsigned long nz, /* number of zero filled bytes in a sector */
			nfill; /* number of fill bytes in a sector */
	int		big_src = 0, /* true if src bigger than dst */
			big_dst = 0, /* true if dst bigger than src */
			is_diff,
			boot_track_too = 0; /* include boot track in compare */
	int		src_status,
			dst_status; /* I/O error returns */
	static unsigned char *src_buff,*dst_buff; /* sector buffers */
	static time_t	from; /* run start time */
	FILE		*log; /* log file */
	int		is_debug = 0,
			log_diffs = 0;
	unsigned char	src_fill_char,
			dst_fill_char; /* fill characters */
	int		fill_char;
	int		src_px,dst_px; /* partition table indices from command line */
	off_t		src_base, /* LBA address of source partition */
			src_n, /* size (number of sectors in) source partition */
		 	dst_base, /* ditto dst */
			dst_n;
	/* range_ptr is used to track a list of ranges. In this case the ranges
	are disk areas specified in LBA addresses */
	range_ptr	d_r = create_range_list(), /* common area sectors that don't match */
			zf_r = create_range_list(), /* zero filled sectors */
			sf_r = create_range_list(), /* sectors with src-fill */
			df_r = create_range_list(), /* sectors with dst-fill */
			of_r = create_range_list(), /* sectors with some other fill */
			o_r = create_range_list(); /* other (unfilled) sectors */
	static char	comment[NAME_LENGTH] = "",
			log_name[NAME_LENGTH] = "cmpptlog.txt",
			access[2] = "a";

/*****************************************************************
get start run time and decode command line
*****************************************************************/
	time(&from);

	if (np < 8) {
		printf ("%s: Missing parameters\n",p[0]);
		print_help(p[0]);
		return 1;
	}

/*****************************************************************
get fill characters from command line
*****************************************************************/

	sscanf (p[5],"%2x",&fill_char);
	src_fill_char = fill_char;
	sscanf (p[7],"%2x",&fill_char);
	dst_fill_char = fill_char;

/*****************************************************************
get options from command line
*****************************************************************/

	for (i = 8; i < np; i++) {
		if (strcmp (p[i],"-h") == 0) help = 1; /* ask for help */
		else if (strcmp (p[i],"-select") == 0) { /* /select src_ix dst_ix */
			i = i + 2;
			if (i >= np) {
				printf ("%s -select requires two parameters: src partition index\n", p[0]);
				printf ("and dst partition index\n");
				help = 1;
			} else {
				sscanf (p[i-1],"%d",&src_px);
				sscanf (p[i],"%d",&dst_px);
				ask_for_partitions = 0; /* we got 'em so don't ask */
			}
		} else if (strcmp (p[i],"-new_log")== 0) access[0] = 'w';
		else if (strcmp (p[i], "-log_name") == 0) {
			if(++i >= np) {
				printf("%s: -log_name option requires a logfile name\n", p[0]);
				help = 1;
			} else strncpy(log_name, p[i], NAME_LENGTH - 1);
		} else if (strcmp (p[i],"-boot")== 0) boot_track_too = 1;
		else if (strcmp (p[i],"-comment")== 0) {
			i++;
			if ( i>=np){
				printf ("%s: comment required with -comment\n",	p[0]);
				help = 1;
			} else strncpy (comment,p[i], NAME_LENGTH - 1);
		} else {
			printf("Invalid parameter: %s\n", p[i]);
			help = 1;
		}
	}
/*****************************************************************
get source and destination drives (in hex) from command line
*****************************************************************/

	strncpy(src_drive, p[4], NAME_LENGTH - 1);
	strncpy(dst_drive, p[6], NAME_LENGTH - 1);

	if (!strcmp(src_drive, dst_drive)) {
		help = 1;
		printf ("Source and destination drives must be different\n");
	}

/*****************************************************************
If there is a problem on command line, then print help message
*****************************************************************/

	if (help) {
		print_help(p[0]);
		return 0;
	} 

/*****************************************************************
Open log file, source disk and destination disk
*****************************************************************/

	log = log_open (log_name, access, comment, SCCS_ID, np, p);
	status = setup_disk (src_drive, "Source disk", log, p, ask_for_partitions,
		 src_px, &src_base, &src_n, &src_disk);
	status = status || setup_disk (dst_drive, "Destination disk", log, p, ask_for_partitions,
		 dst_px, &dst_base, &dst_n, &dst_disk);
	if (status) return 1;

/*****************************************************************
get ready to do the compare
see which is bigger: src or dst
*****************************************************************/
	if (src_n != dst_n) {
		if ( src_n < dst_n) {
			common = src_n;
			big_dst = 1;
		} else {
			common = dst_n;
			big_src = 1;
		}
	} else common = src_n;
	printf ("Source disk fill byte %2X\n", src_fill_char);
	printf ("Destination disk fill byte %2X\n", dst_fill_char);
	fprintf (log, "Source disk fill byte %2X\n", src_fill_char);
	fprintf (log, "Destination disk fill byte %2X\n", dst_fill_char);
	src_lba = src_base;
	dst_lba = dst_base;
	if (boot_track_too) {
		common += 63;
		src_lba -= 63;
		dst_lba -= 63;
		src_base -= 63;
		dst_base -= 63;
		src_n += 63;
		dst_n += 63;
	}
	fprintf (log,"Source base sector %llu Destination base sector %llu\n",
		src_base,dst_base); 
/*****************************************************************
Main compare loop:
	for each sector in common
		read src sector
		read dst sector
		if match then increment match count
		else increment different count
*****************************************************************/
	for (lba = 0; lba < common; lba++) {
		feedback (from, 0, lba, big_dst ? dst_n : common); /* give progress feedback to user */
		is_diff = 0;
		src_status = read_lba(src_disk, src_lba++, &src_buff);
		dst_status = read_lba(dst_disk, dst_lba++, &dst_buff);
		if (src_status || dst_status) {
			fprintf (log,"read error at sector %llu: src %d dst %d\n", lba, src_status, dst_status);
			printf ("read error at lba %llu: src %d dst %d\n", lba, src_status, dst_status);
			return 1;
		}
/*****************************************************************
Compare corresponding sectors
*****************************************************************/

		for (i = 0; i < BYTES_PER_SECTOR; i++) {
			if (src_buff[i] != dst_buff[i]) {
				is_diff = 1;
				byte_diffs++;
			}
		}
		if (is_diff) {
			diffs++;
			add_to_range (d_r,lba);
			if (log_diffs && (diffs <= 50)) {
				 fprintf (log,"%12llu ",lba);
				 if ((diffs%5) == 0) fprintf (log,"\n");
			}
		}
		else {
			match++;
		}
	}
/*****************************************************************
Log results for corresponding sectors
*****************************************************************/

	if  (log_diffs && (diffs)) fprintf (log,"\n");
	fprintf (log,"Sectors compared: %12llu\n",common);
	fprintf (log,"Sectors match:    %12llu\n",match);
	fprintf (log,"Sectors differ:   %12llu\n",diffs);
	fprintf (log,"Bytes differ:     %12llu\n",byte_diffs);
	print_range_list(log,"Diffs range: ",d_r);
	if (big_src) {
		fprintf (log,"Source (%llu) has %llu more sectors than destination (%llu)\n", src_n, src_n - dst_n, dst_n);
	}
/*****************************************************************
If the destination is larger than the source then
	look at the remainder of the destination
*****************************************************************/
	else if (big_dst) {
		fprintf (log,"Source (%llu) has %llu fewer sectors than destination (%llu)\n", src_n, dst_n - src_n, dst_n);
		zero = 0;
		ofill = sfill = dfill = 0;
		other = 0;
		printf ("Destination larger than source; scanning %llu sectors\n", dst_n-common);
		for (lba = common; lba < dst_n; is_debug?(lba+=100):lba++){
			feedback (from, 0, lba, dst_n);
			if((dst_status = read_lba(dst_disk, dst_lba++, &dst_buff))) {
				fprintf (log,"read error at sector %llu: dst %d\n", lba, dst_status);
				printf ("read error at lba %llu: dst %d\n", lba, dst_status);
			}
			nz = 0;
			nfill = 0; 
/*****************************************************************
classify sector: count zero bytes and fill bytes
how to count fill bytes? the rule is: all bytes after
byte [23] are the same. i.e., 488 bytes of the sector are the
same. We use 480 to give some slack.
*****************************************************************/

			for (i = 0; i < BYTES_PER_SECTOR; i++) {
				if ( dst_buff[i] == 0) nz++;
				else if (dst_buff[i] == dst_buff[BUFF_OFF]) nfill++;
			}
			if (nz == BYTES_PER_SECTOR) { zero++; add_to_range(zf_r,lba); }
			else if (nfill > 480) {
					if (dst_buff[BUFF_OFF] == src_fill_char) {
						sfill++;
						add_to_range(sf_r,lba);
					} else if (dst_buff[BUFF_OFF] == dst_fill_char) {
						dfill++;
						add_to_range(df_r,lba);
					} else {
						ofill++;
						add_to_range(of_r,lba);
					}
			}
			else {
				other++;
				add_to_range (o_r,lba);
			}
		}
/*****************************************************************
log results to log file
*****************************************************************/
		if  (log_diffs && (other)) fprintf (log, "\n");
		fprintf (log,"Zero fill:     %llu\n", zero);
		fprintf (log,"Src Byte fill (%02X): %llu\n", src_fill_char, sfill);
		if (src_fill_char == dst_fill_char)
			fprintf (log, "Dst Fill Byte same as Src Fill Byte\n");
		else fprintf (log, "Dst Byte fill (%02X): %lu\n", dst_fill_char, dfill);
		fprintf (log,"Other fill:    %llu\n", ofill);
		fprintf (log,"Other no fill: %llu\n", other);
		print_range_list(log,"Zero fill range: ", zf_r);
		print_range_list(log,"Src fill range: ", sf_r);
		print_range_list(log,"Dst fill range: ", df_r);
		print_range_list(log,"Other fill range: ", of_r);
		print_range_list(log,"Other not filled range: ", o_r);
	}
	log_close(log, from);
	return 0;
}
/**
 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
 * @state
 * @gpt is a GPT header ptr, filled on return.
 * @ptes is a PTEs ptr, filled on return.
 * Description: Returns 1 if valid, 0 on error.
 * If valid, returns pointers to newly allocated GPT header and PTEs.
 * Validity depends on PMBR being valid (or being overridden by the
 * 'gpt' kernel command line option) and finding either the Primary
 * GPT header and PTEs valid, or the Alternate GPT header and PTEs
 * valid.  If the Primary GPT header is not valid, the Alternate GPT header
 * is not checked unless the 'gpt' kernel command line option is passed.
 * This protects against devices which misreport their size, and forces
 * the user to decide to use the Alternate GPT.
 */
static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
			  gpt_entry **ptes)
{
	int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
	gpt_header *pgpt = NULL, *agpt = NULL;
	gpt_entry *pptes = NULL, *aptes = NULL;
	legacy_mbr *legacymbr;
	u64 lastlba;

	if (!ptes)
		return 0;

	lastlba = last_lba(state->bdev);
        if (!force_gpt) {
                /* This will be added to the EFI Spec. per Intel after v1.02. */
                legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL);
                if (legacymbr) {
                        read_lba(state, 0, (u8 *) legacymbr,
				 sizeof (*legacymbr));
                        good_pmbr = is_pmbr_valid(legacymbr);
                        kfree(legacymbr);
                }
                if (!good_pmbr)
                        goto fail;
        }

	good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
				 &pgpt, &pptes);
        if (good_pgpt)
		good_agpt = is_gpt_valid(state,
					 le64_to_cpu(pgpt->alternate_lba),
					 &agpt, &aptes);
        if (!good_agpt && force_gpt)
                good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);

        /* The obviously unsuccessful case */
        if (!good_pgpt && !good_agpt)
                goto fail;

        compare_gpts(pgpt, agpt, lastlba);

        /* The good cases */
        if (good_pgpt) {
                *gpt  = pgpt;
                *ptes = pptes;
                kfree(agpt);
                kfree(aptes);
                if (!good_agpt) {
                        printk(KERN_WARNING 
			       "Alternate GPT is invalid, "
                               "using primary GPT.\n");
                }
                return 1;
        }
        else if (good_agpt) {
                *gpt  = agpt;
                *ptes = aptes;
                kfree(pgpt);
                kfree(pptes);
                printk(KERN_WARNING 
                       "Primary GPT is invalid, using alternate GPT.\n");
                return 1;
        }

 fail:
        kfree(pgpt);
        kfree(agpt);
        kfree(pptes);
        kfree(aptes);
        *gpt = NULL;
        *ptes = NULL;
        return 0;
}
Example #3
0
/******************************************************************************
Compare a source chunk to a destination chunk
log number of sectors compared, # match, # diff, etc
If dst is larger, (almost certain) then run scan_region on excess sectors
******************************************************************************/
int cmp_region (FILE *log, /* the log file */
	/* source parameters: disk, chunk description, fill char */
	disk_control_ptr src_disk, layout_ptr src, char src_fill,
	/* destination parameters: disk, chunk description, fill char */
	disk_control_ptr dst_disk, layout_ptr dst, char dst_fill,
	time_t start_time, /* time the program started running (for user feedback) */
	totals_ptr t) /* summary totals */
{
	unsigned char	*src_buff,
			*dst_buff; /* sector read buffers */
	int		src_status,
			dst_status;  /* disk read status return */
	off_t		lba = 0, /* index for main loop; relative sector in partition */
			common, /* number of sectors with both a src and dst sector */
			diffs = 0, /* number of sectors that differ */
			src_lba,  /* absolute LBA of src sector */
			dst_lba,  /* absolute LBA of dst sector */
			byte_diffs = 0, /* number of bytes that differ */
			match = 0; /* number of sectors that match */
	int		big_src = 0, /* src is bigger than dst */
			big_dst = 0, /* dst is bigger than src */
			is_diff, /* src and dst do not match */
			i; /* loop index */
	range_ptr	d_r = create_range_list(); /* sectors that do not match */

	if (src->n_sectors == dst->n_sectors) common = src->n_sectors;
	else if (src->n_sectors > dst->n_sectors) {
		common = dst->n_sectors;
		big_src = 1;
	} else {
		common = src->n_sectors;
		big_dst = 1;
	}
	src_lba = src->lba_start;
	dst_lba = dst->lba_start;
	fprintf (log,"Src base %llu Dst base %llu\n",
		src_lba,dst_lba);
	for (lba = 0; lba < common;lba++) { /* main loop: scan sectors that correspond */
		is_diff = 0;
		feedback(start_time,0,dst_lba,n_sectors(dst_disk));
		src_status = read_lba(src_disk,src_lba++,&src_buff);
		dst_status = read_lba(dst_disk,dst_lba++,&dst_buff);
		if (src_status) {
			fprintf (log,"src read error 0x%02X on track starting at lba %llu\n",src_status,lba);
			printf ("src read error 0x%02X on track starting at lba %llu\n",src_status,lba);
		}
		if (dst_status) {
			fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n",dst_status,lba);
			printf ("dst read error 0x%02X on track starting at lba %llu\n",dst_status,lba);
		}
		if(src_status || dst_status) return 1;

		/* scan the sectors; note any diffs */
		for (i = 0; i < BYTES_PER_SECTOR; i++) {
			if (src_buff[i] != dst_buff[i]) {
				is_diff = 1;
				byte_diffs++;
			}
		}
		if (is_diff) { /* rats! not a match */
			diffs++;
			add_to_range (d_r,lba);
		} else { /* the source and dst are the same */
			match++;
		}
	} /* log results */
	fprintf (log,"Sectors compared: %12llu\n",common);
	fprintf (log,"Sectors match:    %12llu\n",match);
	fprintf (log,"Sectors differ:   %12llu\n",diffs);
	fprintf (log,"Bytes differ:     %12llu\n",byte_diffs);
	print_range_list(log,"Diffs range: ",d_r);
	if (big_src) {
		fprintf (log,"Source (%llu) has %llu more sectors than destination (%llu)\n",
			src->n_sectors,src->n_sectors - dst->n_sectors,
			dst->n_sectors);
	} else if (big_dst) { /* dst has more sectors to examine */
		fprintf (log,"Source (%llu) has %llu fewer sectors than destination (%llu)\n",
			src->n_sectors,dst->n_sectors - src->n_sectors,
			dst->n_sectors);
		printf ("Source (%llu) has %llu fewer sectors than destination (%llu)\n",
			src->n_sectors,dst->n_sectors - src->n_sectors,
			dst->n_sectors);
		if (dst->chunk_class == CHUNK_UNALLOCATED) /* look at excess sectors in chunk */
			scan_region (log, dst_disk,dst_lba,dst->lba_start + dst->n_sectors,
				src_fill, dst_fill,start_time,
				&t->excess_zero,&t->excess_non_zero);
		else scan_region (log, dst_disk,dst_lba,dst->lba_start + dst->n_sectors,
				src_fill, dst_fill,start_time,
				&t->fill_zero,&t->fill_non_zero);
	}
/******************************************************************************
Update summary totals
******************************************************************************/
	if (dst->chunk_class == CHUNK_PARTITION) { /* partition summary */
		t->n_partitions++;
		t->partition_diffs += diffs;
		t->n_common += common;
	} else if (dst->chunk_class == CHUNK_UNALLOCATED) { /* nothing to do for unallocated chunk */ 
		t->n_unalloc++;
		t->unalloc_diffs += diffs;
		t->n_common_unalloc += common;
	} else { /* boot track summary */
		t->n_boot_tracks++;
		t->boot_track_diffs += diffs;
	}
	return 0;
}
Example #4
0
/******************************************************************************
Examine a part of the destination disk that does not correspond to any area
on the source disk. This is either (1) the sectors of a destination chunk that
do not correspond to the source sectors of the corresponding chunk. or
(2) destination chunk of sectors not allocated to a corresponding source chunk.
To say this another way, source partitions are compared to destination partitions
that are a little larger. Sectors in (1) above are the excess destination sectors.
If the source has unallocated (i.e., not in a partition) sectors between two
partitions, the area between is treated as a partition. Sectors in (2) are the
excess sectors after the last partition on the destination.
******************************************************************************/
void scan_region (FILE *log, /* the log file */
	disk_control_ptr dst_disk, /* the destination disk */
	off_t		common,  /* starting sector LBA address */
	off_t		dst_n,   /* number of sectors to scan */
	unsigned char	src_fill_char, /* the source fill character */
	unsigned char	dst_fill_char, /* the destination fill character */
	time_t		start_time, /* time the program started running */
	off_t		*tz, /* update value: running total of zero fill sectors */
	off_t		*tnz) /* update value: running total of non-zero sectors */
{
	range_ptr	zf_r = create_range_list(), /* range of zero fill sectors */
			sf_r = create_range_list(), /* range of source fill sectors */
			df_r = create_range_list(), /* range of destination fill sectors */
			of_r = create_range_list(), /* range of other fill sectors */
			o_r = create_range_list(); /* range of other sectors */
	unsigned char	*dst_buff, /* the sector to scan */
			other_fill_char = 0; /* last other fill char seen */
	int		dst_status; /* disk I/O status return */
	off_t		lba = 0, /* the sector relative to start address */
			nz,  /* count of zero bytes in a sector */
			nfill, /* count of fill bytes in a sector */
			dst_lba, /* the absolute lba of sector to examine */
			zero = 0, /* number of zero sectors */
			sfill = 0, /* number of sectors filled with source byte */
			dfill = 0, /* number of sectors filled with dst byte */
			ofill = 0, /* number of sectors filled with something else */
			other = 0; /* count of other sectors */
	int		i, /* look index */
			other_fill_seen = 0, /* flag indicating fill other than src/dst */
			new_fill = 0;

	printf ("scanning %llu unmatched sectors: %llu--%llu\n",dst_n-common,common,dst_n);
	fprintf (log,"scanning %llu unmatched sectors: %llu--%llu\n",dst_n-common,common,dst_n);

/******************************************************************************
Loop to scan dst_n sectors from common up to common + dst_n
******************************************************************************/
	dst_lba = common;
	for (lba = common; lba < dst_n; lba++) {
		feedback (start_time,0,dst_lba,n_sectors(dst_disk));
		dst_status = read_lba(dst_disk,dst_lba++,&dst_buff);
		if (dst_status) {
			fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n",dst_status,dst_lba-1);
			printf ("dst read error 0x%02X on track starting at lba %llu\n",dst_status,dst_lba-1);
			exit(1);
		}
		nz = 0;
		nfill = 0;
/******************************************************************************
scan the sector, count number of zero bytes and number of fill bytes.
To count fill bytes: assume sector is filled (from diskwipe) then ...
bytes 1-27 has the sector address and the remaining bytes are the same.
so pick byte # 30 and count the number of bytes that match dst_buff[30],
if enough match (480) then call it filled. The magic constants 30 and 480
allow some room for diskwipe to be off by a few bytes.
******************************************************************************/
		for (i = 0; i < BYTES_PER_SECTOR; i++) {
			if ( dst_buff[i] == 0) nz++;
			else if (dst_buff[i] == dst_buff[BUFF_OFF]) nfill++;
		}
		if (nz == BYTES_PER_SECTOR) { zero++; add_to_range(zf_r,lba); } /* zero sector */
		else if ((nfill > 480) && (dst_buff[BUFF_OFF] != 0x00)) { /* filled sector */
			if (dst_buff[BUFF_OFF] == src_fill_char) { /* src fill */
				sfill++;
				add_to_range(sf_r,lba);
			} else if (dst_buff[BUFF_OFF] == dst_fill_char) { /* dst fill */
				dfill++;
				add_to_range(df_r,lba);
			} else { /* filled with something other than src or dst!! */
				ofill++;
				add_to_range(of_r,lba);
				if (other_fill_seen) {
					if (dst_buff[BUFF_OFF] != other_fill_char) new_fill = 1;
				} else {  /* remember the other fill char */
					other_fill_char = dst_buff[BUFF_OFF];
					new_fill = 0;
				}
			}
		} else {
			other++; /* not zero and not filled */
			add_to_range (o_r,lba);
		}
	}
/******************************************************************************
Log results
******************************************************************************/
	fprintf (log,"Zero fill:           %llu\n",zero);
	fprintf (log,"Src Byte fill (%02X): %llu\n",src_fill_char,sfill);
	if (src_fill_char == dst_fill_char )
		fprintf (log,"Dst Fill Byte same as Src Fill Byte\n");
	else fprintf (log,"Dst Byte fill (%02X): %llu\n",dst_fill_char,dfill);
	fprintf (log,"Other fill   %c(%02X): %llu\n",new_fill?'+':' ',
		other_fill_char,ofill);
	fprintf (log,"Other no fill:        %llu\n",other);
	print_range_list (log,"Zero fill range: ",zf_r);
	print_range_list (log,"Src fill range: ",sf_r);
	print_range_list (log,"Dst fill range: ",df_r);
	print_range_list (log,"Other fill range: ",of_r);
	print_range_list (log,"Other not filled range: ",o_r);

/******************************************************************************
Update running totals for summary
******************************************************************************/
	*tz = *tz + zero;
	*tnz = *tnz + sfill + dfill + ofill + other;
}
Example #5
0
/**
 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
 * @bdev
 * @gpt is a GPT header ptr, filled on return.
 * @ptes is a PTEs ptr, filled on return.
 * Description: Returns 1 if valid, 0 on error.
 * If valid, returns pointers to newly allocated GPT header and PTEs.
 * Validity depends on finding either the Primary GPT header and PTEs valid,
 * or the Alternate GPT header and PTEs valid, and the PMBR valid.
 */
static int
find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
{
	int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
	gpt_header *pgpt = NULL, *agpt = NULL;
	gpt_entry *pptes = NULL, *aptes = NULL;
	legacy_mbr *legacymbr = NULL;
	u64 lastlba;
	if (!bdev || !gpt || !ptes)
		return 0;

	lastlba = last_lba(bdev);
	good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
				 &pgpt, &pptes);
        if (good_pgpt) {
		good_agpt = is_gpt_valid(bdev,
                                         le64_to_cpu(pgpt->alternate_lba),
					 &agpt, &aptes);
                if (!good_agpt) {
                        good_agpt = is_gpt_valid(bdev, lastlba,
                                                 &agpt, &aptes);
                }
        }
        else {
                good_agpt = is_gpt_valid(bdev, lastlba,
                                         &agpt, &aptes);
        }

        /* The obviously unsuccessful case */
        if (!good_pgpt && !good_agpt) {
                goto fail;
        }

	/* This will be added to the EFI Spec. per Intel after v1.02. */
        legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
        if (legacymbr) {
                memset(legacymbr, 0, sizeof (*legacymbr));
                read_lba(bdev, 0, (u8 *) legacymbr,
                         sizeof (*legacymbr));
                good_pmbr = is_pmbr_valid(legacymbr);
                kfree(legacymbr);
                legacymbr=NULL;
        }

        /* Failure due to bad PMBR */
        if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
                printk(KERN_WARNING 
                       "  Warning: Disk has a valid GPT signature "
                       "but invalid PMBR.\n");
                printk(KERN_WARNING
                       "  Assuming this disk is *not* a GPT disk anymore.\n");
                printk(KERN_WARNING
                       "  Use gpt kernel option to override.  "
                       "Use GNU Parted to correct disk.\n");
                goto fail;
        }

        /* Would fail due to bad PMBR, but force GPT anyhow */
        if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
                printk(KERN_WARNING
                       "  Warning: Disk has a valid GPT signature but "
                       "invalid PMBR.\n");
                printk(KERN_WARNING
                       "  Use GNU Parted to correct disk.\n");
                printk(KERN_WARNING
                       "  gpt option taken, disk treated as GPT.\n");
        }

        compare_gpts(pgpt, agpt, lastlba);

        /* The good cases */
        if (good_pgpt && (good_pmbr || force_gpt)) {
                *gpt  = pgpt;
                *ptes = pptes;
                if (agpt)  { kfree(agpt);   agpt = NULL; }
                if (aptes) { kfree(aptes); aptes = NULL; }
                if (!good_agpt) {
                        printk(KERN_WARNING 
			       "Alternate GPT is invalid, "
                               "using primary GPT.\n");
                }
                return 1;
        }
        else if (good_agpt && (good_pmbr || force_gpt)) {
                *gpt  = agpt;
                *ptes = aptes;
                if (pgpt)  { kfree(pgpt);   pgpt = NULL; }
                if (pptes) { kfree(pptes); pptes = NULL; }
                printk(KERN_WARNING 
                       "Primary GPT is invalid, using alternate GPT.\n");
                return 1;
        }

 fail:
        if (pgpt)  { kfree(pgpt);   pgpt=NULL; }
        if (agpt)  { kfree(agpt);   agpt=NULL; }
        if (pptes) { kfree(pptes); pptes=NULL; }
        if (aptes) { kfree(aptes); aptes=NULL; }
        *gpt = NULL;
        *ptes = NULL;
        return 0;
}
Example #6
0
main (int np, char **p) {
	char		src_drive[NAME_LENGTH],
			dst_drive[NAME_LENGTH]; /* drive devices */
	int		help = 0,
			status,
			i;
	static disk_control_ptr src_disk,
			dst_disk; /* disk information */
	off_t		lba = 0, /* index for looping through disk sectors */
			common, /* number of sectors common to source and dst */
			diffs = 0, /* number of sectors that do not match */
			nz, /* number of zero bytes in current sector */
			nfill,/* number of filled bytes in current sector */
			src_ns,dst_ns, /* number of sectors on src and dst */
		/* counts: sectors that ... */
			byte_diffs = 0,
			match = 0,
			zero = 0,
			sfill = 0,
			dfill = 0,
			ofill = 0,
			other = 0;
	int		big_src = 0,
			big_dst = 0,
			is_diff,
			src_status,
			dst_status; /* read status codes (should be zero) */
	static unsigned char *src_buff,
			*dst_buff; /* current src and dst sector data */
	static time_t	from; /* program start time */
	FILE		*log;  /* the log file */
	int		is_debug = 0;
	unsigned char	other_fill_char,
			src_fill_char,
			dst_fill_char; /* the fill characters */
	int		fill_char,
			other_fill_seen = 0;
	off_t		n_src_err = 0,
			n_dst_err = 0; /* count of number of read errs */
	char		comment[NAME_LENGTH] = "",
			access[2] = "a"; /* the user comment */
	char		log_name[NAME_LENGTH] = "cmplog.txt";
								/* sectors that ... */
	range_ptr d_r = create_range_list(), /* ... differ (do not match) */
			zf_r = create_range_list(), /* ... zeros filled */
			sf_r = create_range_list(),/* ... source filled */
			df_r = create_range_list(), /* ... dst filled */
			of_r = create_range_list(), /* ... filled with something else */
			o_r = create_range_list(); /* ... are not filled */

	time(&from);
	src_disk = dst_disk = NULL;

/*****************************************************************
Get the command line
*****************************************************************/
	if (np < 8) {
		print_help(p[0]); /* not enough parameters */
		return 1;
	}

	strncpy(src_drive, p[4], NAME_LENGTH - 1);
	strncpy(dst_drive, p[6], NAME_LENGTH - 1);

	printf ("Src drive %s dst drive %s\n",src_drive,dst_drive);

	sscanf (p[5],"%2x",&fill_char);
	src_fill_char = fill_char;
	sscanf (p[7],"%2x",&fill_char);
	dst_fill_char = fill_char;

	printf ("Src fill 0x%02X dst fill 0x%02X\n",src_fill_char,dst_fill_char);

	for (i = 8; i < np; i++) { /* optional parameters */
		if (strcmp (p[i],"-h") == 0) help = 1;
		else if (strcmp (p[i],"-debug")== 0) is_debug = 1;
		else if (strcmp (p[i],"-new_log")== 0) access[0] = 'w';
		else if (strcmp (p[i], "-log_name") == 0) {
			if(++i >= np) {
				printf("%s: -log_name option requires a logfile name\n", p[0]);
				help = 1;
			} else strncpy(log_name, p[i], NAME_LENGTH - 1);
		} else if (strcmp (p[i],"-comment")== 0) {
			if (++i >= np) {
				printf ("%s: comment required with -comment\n",	p[0]);
				help = 1;
			} else strncpy (comment, p[i], NAME_LENGTH - 1);
		} else {
			printf("Invalid parameter: %s\n", p[i]);
			help = 1;
		}
	}
	if (help) {
		print_help(p[0]);
		return 0;
	}
/*****************************************************************
Start log file
*****************************************************************/
	log = log_open(log_name,access,comment,SCCS_ID,np,p);
	src_disk = open_disk (src_drive,&status);
	if (status) {
		printf ("%s could not access src drive %s status code %d\n",
			p[0],src_drive,status);
		fprintf (log,"%s could not access src drive %s status code %d\n",
			p[0],src_drive,status);
		return 1;
	}
	log_disk(log,"Source",src_disk);
	dst_disk = open_disk (dst_drive,&status);
	if (status){
		printf ("%s could not access dst drive %s status code %d\n",
			p[0],dst_drive,status);
		fprintf (log,"%s could not access dst drive %s status code %d\n",
			p[0],dst_drive,status);
		return 1;
	}
	log_disk(log,"Destination",dst_disk);
	src_ns = n_sectors(src_disk);
	dst_ns = n_sectors(dst_disk);

	if (src_ns != dst_ns){
		if ( src_ns < dst_ns){
			common = src_ns;
			big_dst = 1;
		}
		else {
			common = dst_ns;
			big_src = 1;
		}
	}
	else common = src_ns; 
/*****************************************************************
Main scan loop: read corresponding sectors and compare
*****************************************************************/
	for (lba = 0; lba < common; is_debug?(lba+=100):lba++){
		is_diff = 0;
		feedback (from,0,lba,big_dst?dst_ns:common);
		src_status = read_lba(src_disk,lba,&src_buff);
		dst_status = read_lba(dst_disk,lba,&dst_buff);
		if (src_status) { /* if bad sectors, keep list of first 10 */
			n_src_err++;
			if (n_src_err < 11) {
				fprintf (log,"src read error 0x%02X on track starting at lba %llu\n",
					src_status,lba);
				printf ("src read error 0x%02X at lba %llu\n",src_status,lba);
			} else if (n_src_err == 11) {
				fprintf (log,"... more src read errors\n");
				printf ("... more src read errors\n");
			}
			continue;
		}
		if (dst_status) { /* if bad sectors, keep list of first 10 */
			n_dst_err++;
			if (n_dst_err < 11) {
				fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n",
					dst_status,lba);
				printf ("dst read error 0x%02X at lba %llu\n",dst_status,lba);
			} else if (n_dst_err == 11) {
				fprintf (log,"... more dst read errors\n");
				printf ("... more dst read errors\n");
			}
			continue;
		}
		for (i = 0; i < BYTES_PER_SECTOR; i++){  /* count bytes different */
			if (src_buff[i] != dst_buff[i]){
				is_diff = 1;
				byte_diffs++;
			}
		}
		if (is_diff){/* sectors do not match */
			diffs++;
			add_to_range (d_r,lba);
		}
		else {
			match++;
		}
	}
	/* log results for corresponding sectors */
	fprintf (log,"Sectors compared: %8llu\n",common);
	fprintf (log,"Sectors match:    %8llu\n",match);
	fprintf (log,"Sectors differ:   %8llu\n",diffs);
	if (n_src_err + n_dst_err){ /* note any I/O errors */
		fprintf (log, "Sectors skipped:  %8llu (due to %llu src & %llu dst I/O errors)\n",
			n_src_err+n_dst_err,n_src_err,n_dst_err);
	}
	fprintf (log,"Bytes differ:     %8llu\n",byte_diffs);
	print_range_list(log,"Diffs range",d_r);
	if (big_src){
		fprintf (log,"Source (%llu) has %llu more sectors than destination (%llu)\n",
			src_ns,src_ns - dst_ns,
			dst_ns);
	}
	else if (big_dst){ /* examine remainder of a larger destination */
		fprintf (log,"Source (%llu) has %llu fewer sectors than destination (%llu)\n",
			src_ns,dst_ns - src_ns,
			dst_ns);
		zero = 0;
		ofill = sfill = dfill = 0;
		other = 0;
		printf ("Destination larger than source; scanning %llu sectors\n",
			dst_ns-common);
		for (lba = common; lba < dst_ns; is_debug?(lba+=100):lba++){
			feedback (from,0,lba,dst_ns);
			dst_status = read_lba(dst_disk,lba,&dst_buff);
			if (dst_status){
				n_dst_err++;
				if (n_dst_err < 11){
					fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n",
						dst_status,lba);
					printf ("dst read error 0x%02X at lba %llu\n",dst_status,lba);
				}
				if (n_dst_err == 11) {
					fprintf (log,"... more dst read errors\n");
					printf ("... more dst read errors\n");
				}
				continue;
			}
			nz = 0;
			nfill = 0;
			for (i = 0; i < BYTES_PER_SECTOR; i++) {
				if (dst_buff[i] == 0) nz++;
				else if (dst_buff[i] == dst_buff[BUFF_OFF]) nfill++;
			}
			if (nz == BYTES_PER_SECTOR) {zero++; add_to_range(zf_r,lba);}
			else if (nfill > 480){  /* filled sector: figure out src, dst or other */
					if (dst_buff[BUFF_OFF] == src_fill_char){
						sfill++;
						add_to_range(sf_r,lba);
					}
					else if (dst_buff[BUFF_OFF] == dst_fill_char){
						dfill++;
						add_to_range(df_r,lba);
					}
					else {
						ofill++;
						add_to_range(of_r,lba);
						other_fill_seen = 1;
						other_fill_char = dst_buff[BUFF_OFF];
					}
			} else {
				other++;
				add_to_range (o_r,lba);
			}
		}
		/* log results of scan of extra dst sectors */
		fprintf (log,"Zero fill:          %8llu\n",zero);
		fprintf (log,"Src Byte fill (%02X): %8llu\n",src_fill_char,sfill);
		if (src_fill_char == dst_fill_char)
			fprintf (log,"Dst Fill Byte same as Src Fill Byte\n");
		else fprintf (log,"Dst Byte fill (%02X): %8llu\n",dst_fill_char,dfill);
		if (other_fill_seen)
				fprintf (log,"Other fill (%02X):    %8llu\n",other_fill_char,ofill);
		else fprintf (log,"Other fill:         %8llu\n",ofill);
		fprintf (log,"Other no fill:      %8llu\n",other);
		print_range_list (log,"Zero fill range: ",zf_r);
		print_range_list (log,"Src fill range: ",sf_r);
		print_range_list (log,"Dst fill range: ",df_r);
		print_range_list (log,"Other fill range: ",of_r);
		print_range_list (log,"Other not filled range: ",o_r);
	}
	fprintf (log,"%llu source read errors, %llu destination read errors\n",
		n_src_err,n_dst_err);

	log_close(log,from);
	return 0;
}
Example #7
0
File: gpt.c Project: btian1/efivar
/**
 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
 * @fd  is an open file descriptor to the whole disk
 * @gpt is a GPT header ptr, filled on return.
 * @ptes is a PTEs ptr, filled on return.
 * Description: Returns 1 if valid, 0 on error.
 * If valid, returns pointers to newly allocated GPT header and PTEs.
 * Validity depends on finding either the Primary GPT header and PTEs valid,
 * or the Alternate GPT header and PTEs valid, and the PMBR valid.
 */
static int
find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes,
	       int ignore_pmbr_err)
{
	int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
	gpt_header *pgpt = NULL, *agpt = NULL;
	gpt_entry *pptes = NULL, *aptes = NULL;
	legacy_mbr *legacymbr = NULL;
	uint64_t lastlba;
	int ret = -1;

	errno = EINVAL;

	if (!gpt || !ptes)
		return -1;

	lastlba = last_lba(fd);
	good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
				 &pgpt, &pptes);
	if (good_pgpt) {
		good_agpt = is_gpt_valid(fd,
					 __le64_to_cpu(pgpt->alternate_lba),
					 &agpt, &aptes);
		if (!good_agpt) {
			good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes);
		}
	} else {
		good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes);
	}

	/* The obviously unsuccessful case */
	if (!good_pgpt && !good_agpt) {
		goto fail;
	}

	/* This will be added to the EFI Spec. per Intel after v1.02. */
	legacymbr = malloc(sizeof (*legacymbr));
	if (legacymbr) {
		memset(legacymbr, 0, sizeof (*legacymbr));
		read_lba(fd, 0, (uint8_t *) legacymbr, sizeof (*legacymbr));
		good_pmbr = is_pmbr_valid(legacymbr);
		free(legacymbr);
		legacymbr=NULL;
	}

	/* Failure due to bad PMBR */
	if ((good_pgpt || good_agpt) && !good_pmbr && !ignore_pmbr_err) {
		if (report_errors)
			fprintf(stderr,
			      "Primary GPT is invalid, using alternate GPT.\n");
		goto fail;
	}

	/* Would fail due to bad PMBR, but force GPT anyhow */
	if ((good_pgpt || good_agpt) && !good_pmbr && ignore_pmbr_err &&
	    report_errors) {
		fprintf(stderr,
		 "  Warning: Disk has a valid GPT signature but invalid PMBR.\n"
		 "  Use GNU Parted to correct disk.\n"
		 "  gpt option taken, disk treated as GPT.\n");
	}

	compare_gpts(pgpt, agpt, lastlba);

	/* The good cases */
	if (good_pgpt && (good_pmbr || ignore_pmbr_err)) {
		*gpt  = pgpt;
		*ptes = pptes;
	} else if (good_agpt && (good_pmbr || ignore_pmbr_err)) {
		*gpt  = agpt;
		*ptes = aptes;
	}

	ret = 0;
	errno = 0;
 fail:
	if (pgpt && (pgpt != *gpt || ret < 0)) {
		free(pgpt);
		pgpt=NULL;
	}
	if (pptes && (pptes != *ptes || ret < 0)) {
		free(pptes);
		pptes=NULL;
	}
	if (agpt && (agpt != *gpt || ret < 0)) {
		free(agpt);
		agpt=NULL;
	}
	if (aptes && (aptes != *ptes || ret < 0)) {
		free(aptes);
		aptes=NULL;
	}
	if (ret < 0) {
		*gpt = NULL;
		*ptes = NULL;
	}
	return ret;
}