1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * diskscan: 31*0Sstevel@tonic-gate * performs a verification pass over a device specified on command line; 32*0Sstevel@tonic-gate * display progress on stdout, and print bad sector numbers to stderr 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate #include <stdio.h> 35*0Sstevel@tonic-gate #include <stdlib.h> 36*0Sstevel@tonic-gate #include <fcntl.h> 37*0Sstevel@tonic-gate #include <unistd.h> 38*0Sstevel@tonic-gate #include <stropts.h> 39*0Sstevel@tonic-gate #include <memory.h> 40*0Sstevel@tonic-gate #include <ctype.h> 41*0Sstevel@tonic-gate #include <malloc.h> 42*0Sstevel@tonic-gate #include <signal.h> 43*0Sstevel@tonic-gate #include <sys/types.h> 44*0Sstevel@tonic-gate #include <sys/param.h> 45*0Sstevel@tonic-gate #include <sys/stat.h> 46*0Sstevel@tonic-gate #include <sys/vtoc.h> 47*0Sstevel@tonic-gate #include <sys/dkio.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate static void verexit(); /* signal handler and exit routine */ 50*0Sstevel@tonic-gate static void report(); /* tell user how we're getting on */ 51*0Sstevel@tonic-gate static void scandisk(char *device, int devfd, int writeflag); 52*0Sstevel@tonic-gate static void report(char *what, int sector); 53*0Sstevel@tonic-gate static void verexit(int code); 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #define TRUE 1 56*0Sstevel@tonic-gate #define FALSE 0 57*0Sstevel@tonic-gate #define VER_WRITE 1 58*0Sstevel@tonic-gate #define VER_READ 2 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate static char *progname; 61*0Sstevel@tonic-gate static struct dk_geom dkg; /* physical device boot info */ 62*0Sstevel@tonic-gate static char replybuf[64]; /* used for user replies to questions */ 63*0Sstevel@tonic-gate static daddr_t unix_base; /* first sector of UNIX System partition */ 64*0Sstevel@tonic-gate static daddr_t unix_size; /* # sectors in UNIX System partition */ 65*0Sstevel@tonic-gate static long numbadrd = 0; /* number of bad sectors on read */ 66*0Sstevel@tonic-gate static long numbadwr = 0; /* number of bad sectors on write */ 67*0Sstevel@tonic-gate static char eol = '\n'; /* end-of-line char (if -n, we set to '\n') */ 68*0Sstevel@tonic-gate static int print_warn = 1; /* should the warning message be printed? */ 69*0Sstevel@tonic-gate static int do_scan = VER_READ; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate void 72*0Sstevel@tonic-gate main(int argc, char *argv[]) { 73*0Sstevel@tonic-gate extern int optind; 74*0Sstevel@tonic-gate int devfd; /* device file descriptor */ 75*0Sstevel@tonic-gate struct stat statbuf; 76*0Sstevel@tonic-gate struct part_info part_info; 77*0Sstevel@tonic-gate int c; 78*0Sstevel@tonic-gate int errflag = 0; 79*0Sstevel@tonic-gate char *device; 80*0Sstevel@tonic-gate progname = argv[0]; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* Don't buffer stdout - we don't want to see bursts */ 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate setbuf(stdout, NULL); 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "Wny")) != -1) 87*0Sstevel@tonic-gate { 88*0Sstevel@tonic-gate switch (c) { 89*0Sstevel@tonic-gate case 'W': 90*0Sstevel@tonic-gate do_scan = VER_WRITE; 91*0Sstevel@tonic-gate break; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate case 'n': 94*0Sstevel@tonic-gate eol = '\r'; 95*0Sstevel@tonic-gate break; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate case 'y': 98*0Sstevel@tonic-gate print_warn = 0; 99*0Sstevel@tonic-gate break; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate default: 102*0Sstevel@tonic-gate ++errflag; 103*0Sstevel@tonic-gate break; 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate if ((argc - optind) < 1) 108*0Sstevel@tonic-gate errflag++; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate if (errflag) { 111*0Sstevel@tonic-gate (void) fprintf(stderr, 112*0Sstevel@tonic-gate "\nUsage: %s [-W] [-n] [-y] <phys_device_name> \n", 113*0Sstevel@tonic-gate progname); 114*0Sstevel@tonic-gate exit(1); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate device = argv[optind]; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate if (stat(device, &statbuf)) { 120*0Sstevel@tonic-gate (void) fprintf(stderr, 121*0Sstevel@tonic-gate "%s: invalid device %s, stat failed\n", progname, device); 122*0Sstevel@tonic-gate perror(""); 123*0Sstevel@tonic-gate exit(4); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 126*0Sstevel@tonic-gate (void) fprintf(stderr, 127*0Sstevel@tonic-gate "%s: device %s is not character special\n", 128*0Sstevel@tonic-gate progname, device); 129*0Sstevel@tonic-gate exit(5); 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate if ((devfd = open(device, O_RDWR)) == -1) { 132*0Sstevel@tonic-gate (void) fprintf(stderr, 133*0Sstevel@tonic-gate "%s: open of %s failed\n", progname, device); 134*0Sstevel@tonic-gate perror(""); 135*0Sstevel@tonic-gate exit(8); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate if ((ioctl(devfd, DKIOCGGEOM, &dkg)) == -1) { 139*0Sstevel@tonic-gate (void) fprintf(stderr, 140*0Sstevel@tonic-gate "%s: unable to get disk geometry.\n", progname); 141*0Sstevel@tonic-gate perror(""); 142*0Sstevel@tonic-gate exit(9); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate if ((ioctl(devfd, DKIOCPARTINFO, &part_info)) == -1) { 145*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to get partition info.\n", 146*0Sstevel@tonic-gate progname); 147*0Sstevel@tonic-gate perror(""); 148*0Sstevel@tonic-gate exit(9); 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate unix_base = part_info.p_start; 152*0Sstevel@tonic-gate unix_size = part_info.p_length; 153*0Sstevel@tonic-gate scandisk(device, devfd, do_scan); 154*0Sstevel@tonic-gate exit(0); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate /* 158*0Sstevel@tonic-gate * scandisk: 159*0Sstevel@tonic-gate * attempt to read every sector of the drive; 160*0Sstevel@tonic-gate * display bad sectors found on stderr 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate static void 164*0Sstevel@tonic-gate scandisk(char *device, int devfd, int writeflag) 165*0Sstevel@tonic-gate { 166*0Sstevel@tonic-gate int trksiz = NBPSCTR * dkg.dkg_nsect; 167*0Sstevel@tonic-gate char *verbuf; 168*0Sstevel@tonic-gate daddr_t cursec; 169*0Sstevel@tonic-gate int cylsiz = dkg.dkg_nsect * dkg.dkg_nhead; 170*0Sstevel@tonic-gate int i; 171*0Sstevel@tonic-gate char *rptr; 172*0Sstevel@tonic-gate long tmpend = 0; 173*0Sstevel@tonic-gate long tmpsec = 0; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate /* #define LIBMALLOC */ 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate #ifdef LIBMALLOC 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate extern int mallopt(); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* This adds 5k to the binary, but it's a lot prettier */ 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* make track buffer sector aligned */ 185*0Sstevel@tonic-gate if (mallopt(M_GRAIN, 0x200)) { 186*0Sstevel@tonic-gate perror("mallopt"); 187*0Sstevel@tonic-gate exit(1); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate if ((verbuf = malloc(NBPSCTR * dkg.dkg_nsect)) == (char *)NULL) { 190*0Sstevel@tonic-gate perror("malloc"); 191*0Sstevel@tonic-gate exit(1); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate #else 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate if ((verbuf = malloc(0x200 + NBPSCTR * dkg.dkg_nsect)) 197*0Sstevel@tonic-gate == (char *)NULL) { 198*0Sstevel@tonic-gate perror("malloc"); 199*0Sstevel@tonic-gate exit(1); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate verbuf = (char *)(((unsigned long)verbuf + 0x00000200) & 0xfffffe00); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate #endif 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate /* write pattern in track buffer */ 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate for (i = 0; i < trksiz; i++) 208*0Sstevel@tonic-gate verbuf[i] = (char)0xe5; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* Turn off retry, and set trap to turn them on again */ 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate (void) signal(SIGINT, verexit); 213*0Sstevel@tonic-gate (void) signal(SIGQUIT, verexit); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate if (writeflag == VER_READ) 216*0Sstevel@tonic-gate goto do_readonly; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate /* 219*0Sstevel@tonic-gate * display warning only if -n arg not passed 220*0Sstevel@tonic-gate * (otherwise the UI system will take care of it) 221*0Sstevel@tonic-gate */ 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate if (print_warn == 1) { 224*0Sstevel@tonic-gate (void) printf( 225*0Sstevel@tonic-gate "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device); 226*0Sstevel@tonic-gate (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n"); 227*0Sstevel@tonic-gate (void) printf(" THAT PARTITION OR SLICE.\n"); 228*0Sstevel@tonic-gate (void) printf("Do you want to continue (y/n)? "); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate rptr = fgets(replybuf, 64*sizeof (char), stdin); 231*0Sstevel@tonic-gate if (!rptr || !((replybuf[0] == 'Y') || (replybuf[0] == 'y'))) 232*0Sstevel@tonic-gate exit(10); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 236*0Sstevel@tonic-gate if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 237*0Sstevel@tonic-gate (void) fprintf(stderr, 238*0Sstevel@tonic-gate "Error seeking sector %ld Cylinder %ld\n", 239*0Sstevel@tonic-gate cursec, cursec / cylsiz); 240*0Sstevel@tonic-gate verexit(1); 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate /* 244*0Sstevel@tonic-gate * verify sector at a time only when 245*0Sstevel@tonic-gate * the whole track write fails; 246*0Sstevel@tonic-gate * (if we write a sector at a time, it takes forever) 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate report("Writing", cursec); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate if (write(devfd, verbuf, trksiz) != trksiz) { 252*0Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 253*0Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 254*0Sstevel@tonic-gate /* 255*0Sstevel@tonic-gate * try writing to it once; if this fails, 256*0Sstevel@tonic-gate * then announce the sector bad on stderr 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate if (lseek 260*0Sstevel@tonic-gate (devfd, (long)tmpsec * NBPSCTR, 0) == -1) { 261*0Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking " 262*0Sstevel@tonic-gate "sector %ld Cylinder %ld\n", 263*0Sstevel@tonic-gate tmpsec, cursec / cylsiz); 264*0Sstevel@tonic-gate verexit(1); 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate report("Writing", tmpsec); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate if (write(devfd, verbuf, NBPSCTR) != NBPSCTR) { 270*0Sstevel@tonic-gate (void) fprintf(stderr, 271*0Sstevel@tonic-gate "%ld\n", tmpsec + unix_base); 272*0Sstevel@tonic-gate numbadwr++; 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate (void) putchar(eol); 279*0Sstevel@tonic-gate do_readonly: 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 282*0Sstevel@tonic-gate if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 283*0Sstevel@tonic-gate (void) fprintf(stderr, 284*0Sstevel@tonic-gate "Error seeking sector %ld Cylinder %ld\n", 285*0Sstevel@tonic-gate cursec, cursec / cylsiz); 286*0Sstevel@tonic-gate verexit(1); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* 290*0Sstevel@tonic-gate * read a sector at a time only when 291*0Sstevel@tonic-gate * the whole track write fails; 292*0Sstevel@tonic-gate * (if we do a sector at a time read, it takes forever) 293*0Sstevel@tonic-gate */ 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate report("Reading", cursec); 296*0Sstevel@tonic-gate if (read(devfd, verbuf, trksiz) != trksiz) { 297*0Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 298*0Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 299*0Sstevel@tonic-gate if (lseek(devfd, (long)tmpsec * NBPSCTR, 0) 300*0Sstevel@tonic-gate == -1) { 301*0Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking" 302*0Sstevel@tonic-gate " sector %ld Cylinder %ld\n", 303*0Sstevel@tonic-gate tmpsec, cursec / cylsiz); 304*0Sstevel@tonic-gate verexit(1); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate report("Reading", tmpsec); 307*0Sstevel@tonic-gate if (read(devfd, verbuf, NBPSCTR) != NBPSCTR) { 308*0Sstevel@tonic-gate (void) fprintf(stderr, "%ld\n", 309*0Sstevel@tonic-gate tmpsec + unix_base); 310*0Sstevel@tonic-gate numbadrd++; 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate (void) printf("%c%c======== Diskscan complete ========%c", eol, 316*0Sstevel@tonic-gate eol, eol); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if ((numbadrd > 0) || (numbadwr > 0)) { 319*0Sstevel@tonic-gate (void) printf("%cFound %ld bad sector(s) on read," 320*0Sstevel@tonic-gate " %ld bad sector(s) on write%c", 321*0Sstevel@tonic-gate eol, numbadrd, numbadwr, eol); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate static void 326*0Sstevel@tonic-gate verexit(int code) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate (void) printf("\n"); 329*0Sstevel@tonic-gate exit(code); 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * report where we are... 335*0Sstevel@tonic-gate */ 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate static void 338*0Sstevel@tonic-gate report(char *what, int sector) 339*0Sstevel@tonic-gate { 340*0Sstevel@tonic-gate (void) printf("%s sector %-7d of %-7ld%c", what, sector, 341*0Sstevel@tonic-gate unix_size, eol); 342*0Sstevel@tonic-gate } 343