bin/96677: Improvements for src/tools/tools/recoverdisk

Ulrich Spoerlein uspoerlein at gmail.com
Thu May 4 22:50:18 UTC 2006


The following reply was made to PR bin/96677; it has been noted by GNATS.

From: Ulrich Spoerlein <uspoerlein at gmail.com>
To: Maxim Konovalov <maxim at macomnet.ru>
Cc: bug-followup at freebsd.org
Subject: Re: bin/96677: Improvements for src/tools/tools/recoverdisk
Date: Thu, 4 May 2006 15:56:17 +0200

 Here's a simple alternative, that only sets a flag in the signal
 handler.
 
 Ulrich Spoerlein
 
 --- recoverdisk.c.orig	Thu Dec 15 19:41:42 2005
 +++ recoverdisk.c	Thu May  4 15:51:08 2006
 @@ -1,4 +1,4 @@
 -/*
 +/*-
   * ----------------------------------------------------------------------------
   * "THE BEER-WARE LICENSE" (Revision 42):
   * <phk at FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 @@ -8,21 +8,29 @@
   *
   * $FreeBSD: src/tools/tools/recoverdisk/recoverdisk.c,v 1.4.4.1 2005/12/15 03:50:03 sobomax Exp $
   */
 +#include <stdbool.h>
  #include <stdio.h>
  #include <stdint.h>
  #include <stdlib.h>
  #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		(1024 * 1024)
 -#define MEDIUMSIZE	(64 * 1024)
 -#define MINSIZE		(512)
 +#define	MIN(a,b) (((a)<(b))?(a):(b))
 +
 +static bool aborting = false;
 +
 +static size_t bigsize = 1024 * 1024;
 +static size_t medsize = 64 * 1024;
 +static size_t minsize = 512;
  
  struct lump {
  	off_t			start;
 @@ -33,7 +41,6 @@
  
  static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
  
 -
  static void
  new_lump(off_t start, off_t len, int state)
  {
 @@ -48,29 +55,128 @@
  	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(void)
 +{
 +	FILE *file;
 +
 +	if (wworklist != NULL) {
 +		(void)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);
 +		}
 +		(void)fprintf(stderr, " done.\n");
 +	}
 +	exit(0);
 +}
 +
 +/* Read the worklist if -r was given */
 +static off_t
 +read_worklist(off_t t)
 +{
 +	off_t s, l, d;
 +	int state, lines;
 +	FILE *file;
 +	
 +	(void)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;
 +	}
 +	(void)fprintf(stderr, " done.\n");
 +
 +	/* 
 +	 * Return the number of bytes already read
 +	 * (at least not in worklist).
 +	 */
 +	return (d);
 +}
 +
 +static void
 +usage(void)
 +{
 +	(void)fprintf(stderr,
 +    "usage: recoverdisk [-r worklist] [-w worklist] source-drive [destination]\n");
 +	exit(EX_USAGE);
 +}
 +
 +static void
 +sighandler(__unused int sig)
 +{
 +	aborting = true;
 +	signal(SIGINT, SIG_DFL);
 +}
 +
  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;
 +	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 || argc > 2)
 +		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)
 @@ -80,46 +186,66 @@
  		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;
 +	}
 +
 +	if (wworklist != NULL) {
 +		signal(SIGINT, sighandler);
 +		/* Has this any effect on pread/pwrite at all? */
 +		siginterrupt(SIGINT, 1);
 +	}
  
  	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;
 +		while (lp->len > 0 && !aborting) {
 +			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,
 @@ -152,9 +278,13 @@
  			lp->start += i;
  			lp->len -= i;
  		}
 +		
 +		if (aborting)
 +			save_worklist();
 +		
 +		TAILQ_REMOVE(&lumps, lp, list);
  		free(lp);
  	}
  	printf("\nCompleted\n");
 -	exit (0);
 +	return (0);
  }
 -


More information about the freebsd-bugs mailing list