Re: Improvements to src/tools/tools/recoverdisk

From: Maxim Sobolev <sobomax_at_FreeBSD.org>
Date: Tue, 25 Apr 2006 12:48:43 -0700
Sounds cool, perhaps it's time to move recoverdisk into the base system 
to give it better exposure?

-Maxim

Ulrich Spoerlein wrote:
> Dear Poul-Henning, current_at_,
> 
> I made two, what I call, improvements to recoverdisk. It only tries to
> read in multiples of 512 bytes OR the sectorsize. This sucks for CD/DVD
> with 2352 bytes sectorsize. My patch takes the native sectorsize into
> account, when dimensioning BIG and MEDIUMSIZE.
> 
> Second feature is the saving and loading of the worklist. Again, not
> very helpful for reading hard disks, but very useful for CDs. This way,
> you can first try a scratched CD in drive A, then drive B and drive C.
> You don't have to start all over again, but instead can profit from the
> different error recovery mechanisms.
> 
> Previously, I did this with dd(1) and paper and pencil. Not funny.
> 
> Please try the attached patch, thanks!
> 
> Ulrich Spoerlein
> 
> 
> ------------------------------------------------------------------------
> 
> --- recoverdisk.orig.c	Mon Apr 24 19:34:57 2006
> +++ recoverdisk.c	Tue Apr 25 14:11:44 2006
> _at__at_ -14,15 +14,20 _at__at_
>  #include <err.h>
>  #include <errno.h>
>  #include <fcntl.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <sysexits.h>
>  #include <time.h>
>  #include <unistd.h>
>  #include <sys/queue.h>
>  #include <sys/disk.h>
>  #include <sys/stat.h>
>  
> -#define BIGSIZE		(1046640)
> -#define MEDIUMSIZE	(63504)
> -#define MINSIZE		(512)
> +#define	MIN(a,b) (((a)<(b))?(a):(b))
> +
> +static off_t bigsize = 1024 * 1024;
> +static off_t medsize = 64 * 1024;
> +static off_t minsize = 512;
>  
>  struct lump {
>  	off_t			start;
> _at__at_ -48,29 +53,119 _at__at_
>  	TAILQ_INSERT_TAIL(&lumps, lp, list);
>  }
>  
> +static struct lump *lp;
> +static char *wworklist = NULL;
> +static char *rworklist = NULL;
> +
> +/* Save the worklist, if -w was given */
> +static void
> +save_worklist(__unused int sig)
> +{
> +	FILE *file;
> +
> +	if (wworklist != NULL) {
> +		fprintf(stderr, "\nSaving worklist ...");
> +		fflush(stderr);
> +
> +		file = fopen(wworklist, "w");
> +		if (file == NULL)
> +			err(1, "Error opening file %s", wworklist);
> +
> +		for (;;) {
> +			lp = TAILQ_FIRST(&lumps);
> +			if (lp == NULL)
> +				break;
> +			fprintf(file, "%jd %jd %d\n",
> +			    (intmax_t)lp->start, (intmax_t)lp->len, lp->state);
> +			TAILQ_REMOVE(&lumps, lp, list);
> +		}
> +		fprintf(stderr, " done.\n");
> +	}
> +	exit(0);
> +}
> +
> +static off_t
> +read_worklist(off_t t)
> +{
> +	off_t s, l, d;
> +	int state, lines;
> +	FILE *file;
> +	
> +	fprintf(stderr, "Reading worklist ...");
> +	fflush(stderr);
> +	file = fopen(rworklist, "r");
> +	if (file == NULL)
> +		err(1, "Error opening file %s", rworklist);
> +
> +	lines = 0;
> +	d = t;
> +	for (;;) {
> +		++lines;
> +		if (3 != fscanf(file, "%jd %jd %d\n", &s, &l, &state)) {
> +			if (!feof(file))
> +				err(1, "Error parsing file %s at line %d",
> +				    rworklist, lines);
> +			else
> +				break;
> +		}
> +
> +		new_lump(s, l, state);
> +		d -= l;
> +	}
> +	fprintf(stderr, " done.\n");
> +
> +	/* 
> +	 * Return the number of bytes already read (at least not in
> +	 * worklist).
> +	 */
> +	return (d);
> +}
> +
> +static void
> +usage(void)
> +{
> +	fprintf(stderr, "Usage: %s [-r worklist] [-w worklist] source-drive [destination]", "recoverdisk");
> +	exit(EX_USAGE);
> +}
> +
>  int
> -main(int argc, const char **argv)
> +main(int argc, char * const argv[])
>  {
> +	int ch;
>  	int fdr, fdw;
> -	struct lump *lp;
>  	off_t 	t, d;
>  	size_t i, j;
>  	int error, flags;
>  	u_char *buf;
> -	u_int sectorsize, minsize;
> +	u_int sectorsize;
>  	time_t t1, t2;
>  	struct stat sb;
>  
> +	while ((ch = getopt(argc, argv, "r:w:")) != -1) {
> +		switch (ch) {
> +			case 'w':
> +				wworklist = strdup(optarg);
> +				if (wworklist == NULL)
> +					err(1, "Cannot allocate enough memory");
> +				break;
> +			case 'r':
> +				rworklist = strdup(optarg);
> +				if (rworklist == NULL)
> +					err(1, "Cannot allocate enough memory");
> +				break;
> +			default:
> +				usage();
> +		}
> +	}
> +	argc -= optind;
> +	argv += optind;
>  
> -	if (argc < 2)
> -		errx(1, "Usage: %s source-drive [destination]", argv[0]);
> +	if (argc < 1)
> +		usage();
>  
> -	buf = malloc(BIGSIZE);
> -	if (buf == NULL)
> -		err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
> -	fdr = open(argv[1], O_RDONLY);
> +	fdr = open(argv[0], O_RDONLY);
>  	if (fdr < 0)
> -		err(1, "Cannot open read descriptor %s", argv[1]);
> +		err(1, "Cannot open read descriptor %s", argv[0]);
>  
>  	error = fstat(fdr, &sb);
>  	if (error < 0)
> _at__at_ -80,46 +175,62 _at__at_
>  		error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
>  		if (error < 0)
>  			err(1, "DIOCGSECTORSIZE failed");
> +
> +		/*
> +		 * Make medsize roughly 64kB, depending on native sector
> +		 * size. bigsize has to be a multiple of medsize.
> +		 * For media with 2352 sectors, this will
> +		 * result in 2352, 63504, and 1016064 bytes.
> +		 */
>  		minsize = sectorsize;
> +		medsize = (medsize / sectorsize) * sectorsize;
> +		bigsize = medsize * 16;
>  
>  		error = ioctl(fdr, DIOCGMEDIASIZE, &t);
>  		if (error < 0)
>  			err(1, "DIOCGMEDIASIZE failed");
>  	} else {
> -		sectorsize = 1;
>  		t = sb.st_size;
> -		minsize = MINSIZE;
>  		flags |= O_CREAT | O_TRUNC;
>  	}
>  
> -	if (argc > 2) {
> -		fdw = open(argv[2], flags, DEFFILEMODE);
> +	buf = malloc(bigsize);
> +	if (buf == NULL)
> +		err(1, "Cannot allocate %jd bytes buffer", (intmax_t)bigsize);
> +
> +	if (argc > 1) {
> +		fdw = open(argv[1], flags, DEFFILEMODE);
>  		if (fdw < 0)
> -			err(1, "Cannot open write descriptor %s", argv[2]);
> +			err(1, "Cannot open write descriptor %s", argv[1]);
>  	} else {
>  		fdw = -1;
>  	}
>  
> -	new_lump(0, t, 0);
> -	d = 0;
> +	if (rworklist != NULL) {
> +		d = read_worklist(t);
> +	} else {
> +		new_lump(0, t, 0);
> +		d = 0;
> +	}
> +
> +	signal(SIGINT, save_worklist);
>  
>  	t1 = 0;
> +	printf("%13s %7s %13s %5s %13s %13s %9s\n",
> +	    "start", "size", "len", "state", "done", "remaining", "% done");
>  	for (;;) {
>  		lp = TAILQ_FIRST(&lumps);
>  		if (lp == NULL)
>  			break;
> -		TAILQ_REMOVE(&lumps, lp, list);
>  		while (lp->len > 0) {
> -			i = BIGSIZE;
> -			if (lp->len < BIGSIZE)
> -				i = lp->len;
> +			i = MIN(lp->len, bigsize);
>  			if (lp->state == 1)
> -				i = MEDIUMSIZE;
> +				i = MIN(lp->len, medsize);
>  			if (lp->state > 1)
> -				i = minsize;
> +				i = MIN(lp->len, minsize);
>  			time(&t2);
> -			if (t1 != t2 || lp->len < BIGSIZE) {
> -				printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f",
> +			if (t1 != t2 || lp->len < bigsize) {
> +				printf("\r%13jd %7zu %13jd %5d %13jd %13jd %.7f",
>  				    (intmax_t)lp->start,
>  				    i, 
>  				    (intmax_t)lp->len,
> _at__at_ -152,9 +263,10 _at__at_
>  			lp->start += i;
>  			lp->len -= i;
>  		}
> +		TAILQ_REMOVE(&lumps, lp, list);
>  		free(lp);
>  	}
>  	printf("\nCompleted\n");
> -	exit (0);
> +	return (0);
>  }
>  
Received on Tue Apr 25 2006 - 17:48:53 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:55 UTC