readall.c

Go to the documentation of this file.
00001 /* readall - read a whole device fast           Author: Andy Tanenbaum */
00002 
00003 /* Readall reads all the blocks on a device as fast as it can.  If it hits
00004  * an error, it stops reading in large units and reads one block at a time.
00005  * It reports on all errors it finds.
00006  *
00007  * If the -b flag is given, the output is a shell script that can be run
00008  * to mark all the bad blocks.
00009  *
00010  * If the -t flag is given, only the total numbers of blocks is reported.
00011  *
00012  * Examples of usage:
00013  *      readall /dev/hd1                # read /dev/hd1
00014  *      readall -b /dev/hd2             # prepare bad block list on stdout
00015  *      readall -t /dev/ram             # report size of ram disk
00016  */
00017 
00018 #include <sys/types.h>
00019 #include <sys/ioc_disk.h>
00020 #include <minix/partition.h>
00021 #include <minix/u64.h>
00022 #include <time.h>
00023 #include <fcntl.h>
00024 #include <unistd.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 
00028 #define CHUNK    25             /* max number of blocks read at once */
00029 #define BLOCK_SIZE      1024    /* size of a block */
00030 #define RESUME  200             /* # good reads before going back to CHUNK */
00031 #define DIVISOR  1000           /* how often to print statistics */
00032 #define STORE  4096             /* save this many bad blocks for summary */
00033 
00034 int chunk = CHUNK;              /* current number of blocks being read */
00035 long goodies;                   /* incremented on good reads */
00036 long errors;                    /* number of errors so far */
00037 int normal = 1;                 /* set unless -b flag is given */
00038 int total = 0;                  /* unset unless -t flag is given */
00039 char *name;                     /* name of special file being read */
00040 
00041 char a[CHUNK * BLOCK_SIZE];     /* read buffer */
00042 long rotten[STORE];             /* list of bad blocks */
00043 
00044 _PROTOTYPE(int main, (int argc, char **argv));
00045 static _PROTOTYPE(void output, (long blocks_read));
00046 
00047 /* print pretty progress meter with remaining no. of blocks and ETA on
00048  * stderr
00049  */
00050 void
00051 prettyprogress(long b, long nblocks, time_t starttime)
00052 {
00053   /* print progress indication */
00054   time_t spent, now;
00055   long bpsec;
00056   time(&now);
00057   spent = now - starttime;
00058   if(spent > 0 && (bpsec = b / spent) > 0) {
00059         int len, i;
00060         long secremain, minremain, hremain;
00061           secremain = (nblocks - b) / bpsec;
00062           minremain = (secremain / 60) % 60;
00063           hremain = secremain / 3600;
00064         len = fprintf(stderr, "Remain %ld blocks. ETA: %d:%02d:%02d  [",
00065                 nblocks - b,
00066                 hremain, minremain, secremain % 60);
00067 #define WIDTH 77
00068         len = WIDTH - len;
00069         for(i = 0; i < (b * (len-1) / nblocks); i++) 
00070                 fprintf(stderr, "=");
00071         fprintf(stderr, "|");
00072         for(; i < len-2; i++) 
00073                 fprintf(stderr, "-");
00074         fprintf(stderr, "]\r");
00075         fflush(stderr);
00076   }
00077 
00078   return;
00079 }
00080 
00081 int main(argc, argv)
00082 int argc;
00083 char *argv[];
00084 {
00085   struct partition entry;
00086   int fd, s, i, badprinted;
00087   long b = 0, nblocks;
00088   char *p;
00089   time_t starttime;
00090 
00091   if (argc != 2 && argc != 3) {
00092         fprintf(stderr, "Usage: readall [-b | -t] file\n");
00093         exit(1);
00094   }
00095   i = 1;
00096 
00097   p = argv[1];
00098   if (*p == '-' && *(p + 1) == 'b' && *(p + 2) == '\0') {
00099         normal = 0;
00100         i++;
00101         name = argv[i];
00102   }
00103   if (*p == '-' && *(p + 1) == 't' && *(p + 2) == '\0') {
00104         normal = 0;
00105         total = 1;
00106         i++;
00107         name = argv[i];
00108   }
00109   fd = open(argv[i], O_RDONLY);
00110   if (fd < 0) {
00111         perror(argv[i]);
00112         fprintf(stderr, "%s is not readable\n", argv[i]);
00113         exit(1);
00114   }
00115 
00116   /* Get size of file */
00117   if(ioctl(fd, DIOCGETP, &entry) < 0) {
00118         perror("ioctl DIOCGETP");
00119         return 1;
00120   }
00121   nblocks = div64u(entry.size, BLOCK_SIZE);
00122 
00123   time(&starttime);
00124   /* Read the entire file. Try it in large chunks, but if an error
00125    * occurs, go to single reads for a while. */
00126   while (1) {
00127         if(lseek(fd, BLOCK_SIZE * b, SEEK_SET) < 0) {
00128                 perror("lseek");
00129                 return 1;
00130         }
00131         s = read(fd, a, BLOCK_SIZE * chunk);
00132         if (s == BLOCK_SIZE * chunk) {
00133                 /* Normal read, no errors. */
00134                 b += chunk;
00135                 goodies++;
00136                 if (chunk == 1) {
00137                         if (goodies >= RESUME && b % DIVISOR == 0)
00138                                 chunk = CHUNK;
00139                 }
00140                 if(b % DIVISOR == 0 && !normal) {
00141                         prettyprogress(b, nblocks, starttime);
00142                 }
00143         } else if (s < 0) {
00144                 /* I/O error. */
00145                 if (chunk != 1) {
00146                         chunk = 1;      /* regress to single block mode */
00147                         continue;
00148                 }
00149                 if (errors == STORE) {
00150                         fprintf(stderr,
00151                          "\n%ld Bad blocks is too many.  Exiting\n",
00152                                 errors);
00153                         exit(1);
00154                 }
00155                 rotten[(int) errors] = b;       /* log the error */
00156                 b += chunk;
00157                 errors++;
00158         } else {
00159                 /* End of file. */
00160                 b += s / BLOCK_SIZE;
00161                 if (normal) {
00162                         output(b);
00163                         fprintf(stderr, "\n");
00164                 } else fprintf(stderr, "\r%*s\n", -WIDTH, "Done scanning.");
00165                 if (total) printf("%8ld\n", b);
00166                 if ((errors == 0) || total) exit(0);
00167                 badprinted = 0;
00168                 if (normal) printf("Summary of bad blocks\n");
00169 
00170                 /* Print summary of bad blocks, possibly as shell script. */
00171                 for (i = 0; i < errors; i++) {
00172                         if (normal == 0 && badprinted == 0) {
00173                                 printf("badblocks %s ", name);
00174                                 badprinted = 1;
00175                         }
00176                         printf("%6ld ", rotten[i]);
00177                         if ((i + 1) % 7 == 0) {
00178                                 printf("\n");
00179                                 badprinted = 0;
00180                         }
00181                 }
00182                 printf("\n");
00183                 exit(0);
00184         }
00185         if (normal && b % DIVISOR == 0) output(b);
00186   }
00187 }
00188 
00189 static void output(blocks_read)
00190 long blocks_read;
00191 {
00192   fprintf(stderr, "%8ld blocks read, %5ld errors\r", blocks_read, errors);
00193   fflush(stderr);
00194 }

Generated on Fri Apr 14 22:57:10 2006 for minix by  doxygen 1.4.6