summaryrefslogtreecommitdiff
path: root/usr/src/cmd/diskscan/diskscan.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/diskscan/diskscan.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/diskscan/diskscan.c')
-rw-r--r--usr/src/cmd/diskscan/diskscan.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/usr/src/cmd/diskscan/diskscan.c b/usr/src/cmd/diskscan/diskscan.c
new file mode 100644
index 0000000000..359ad54911
--- /dev/null
+++ b/usr/src/cmd/diskscan/diskscan.c
@@ -0,0 +1,342 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * diskscan:
+ * performs a verification pass over a device specified on command line;
+ * display progress on stdout, and print bad sector numbers to stderr
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <memory.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/vtoc.h>
+#include <sys/dkio.h>
+
+static void verexit(); /* signal handler and exit routine */
+static void report(); /* tell user how we're getting on */
+static void scandisk(char *device, int devfd, int writeflag);
+static void report(char *what, int sector);
+static void verexit(int code);
+
+#define TRUE 1
+#define FALSE 0
+#define VER_WRITE 1
+#define VER_READ 2
+
+static char *progname;
+static struct dk_geom dkg; /* physical device boot info */
+static char replybuf[64]; /* used for user replies to questions */
+static daddr_t unix_base; /* first sector of UNIX System partition */
+static daddr_t unix_size; /* # sectors in UNIX System partition */
+static long numbadrd = 0; /* number of bad sectors on read */
+static long numbadwr = 0; /* number of bad sectors on write */
+static char eol = '\n'; /* end-of-line char (if -n, we set to '\n') */
+static int print_warn = 1; /* should the warning message be printed? */
+static int do_scan = VER_READ;
+
+void
+main(int argc, char *argv[]) {
+ extern int optind;
+ int devfd; /* device file descriptor */
+ struct stat statbuf;
+ struct part_info part_info;
+ int c;
+ int errflag = 0;
+ char *device;
+ progname = argv[0];
+
+ /* Don't buffer stdout - we don't want to see bursts */
+
+ setbuf(stdout, NULL);
+
+ while ((c = getopt(argc, argv, "Wny")) != -1)
+ {
+ switch (c) {
+ case 'W':
+ do_scan = VER_WRITE;
+ break;
+
+ case 'n':
+ eol = '\r';
+ break;
+
+ case 'y':
+ print_warn = 0;
+ break;
+
+ default:
+ ++errflag;
+ break;
+ }
+ }
+
+ if ((argc - optind) < 1)
+ errflag++;
+
+ if (errflag) {
+ (void) fprintf(stderr,
+ "\nUsage: %s [-W] [-n] [-y] <phys_device_name> \n",
+ progname);
+ exit(1);
+ }
+
+ device = argv[optind];
+
+ if (stat(device, &statbuf)) {
+ (void) fprintf(stderr,
+ "%s: invalid device %s, stat failed\n", progname, device);
+ perror("");
+ exit(4);
+ }
+ if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
+ (void) fprintf(stderr,
+ "%s: device %s is not character special\n",
+ progname, device);
+ exit(5);
+ }
+ if ((devfd = open(device, O_RDWR)) == -1) {
+ (void) fprintf(stderr,
+ "%s: open of %s failed\n", progname, device);
+ perror("");
+ exit(8);
+ }
+
+ if ((ioctl(devfd, DKIOCGGEOM, &dkg)) == -1) {
+ (void) fprintf(stderr,
+ "%s: unable to get disk geometry.\n", progname);
+ perror("");
+ exit(9);
+ }
+ if ((ioctl(devfd, DKIOCPARTINFO, &part_info)) == -1) {
+ (void) fprintf(stderr, "%s: unable to get partition info.\n",
+ progname);
+ perror("");
+ exit(9);
+ }
+
+ unix_base = part_info.p_start;
+ unix_size = part_info.p_length;
+ scandisk(device, devfd, do_scan);
+ exit(0);
+}
+
+/*
+ * scandisk:
+ * attempt to read every sector of the drive;
+ * display bad sectors found on stderr
+ */
+
+static void
+scandisk(char *device, int devfd, int writeflag)
+{
+ int trksiz = NBPSCTR * dkg.dkg_nsect;
+ char *verbuf;
+ daddr_t cursec;
+ int cylsiz = dkg.dkg_nsect * dkg.dkg_nhead;
+ int i;
+ char *rptr;
+ long tmpend = 0;
+ long tmpsec = 0;
+
+/* #define LIBMALLOC */
+
+#ifdef LIBMALLOC
+
+ extern int mallopt();
+
+ /* This adds 5k to the binary, but it's a lot prettier */
+
+
+ /* make track buffer sector aligned */
+ if (mallopt(M_GRAIN, 0x200)) {
+ perror("mallopt");
+ exit(1);
+ }
+ if ((verbuf = malloc(NBPSCTR * dkg.dkg_nsect)) == (char *)NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+#else
+
+ if ((verbuf = malloc(0x200 + NBPSCTR * dkg.dkg_nsect))
+ == (char *)NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ verbuf = (char *)(((unsigned long)verbuf + 0x00000200) & 0xfffffe00);
+
+#endif
+
+ /* write pattern in track buffer */
+
+ for (i = 0; i < trksiz; i++)
+ verbuf[i] = (char)0xe5;
+
+ /* Turn off retry, and set trap to turn them on again */
+
+ (void) signal(SIGINT, verexit);
+ (void) signal(SIGQUIT, verexit);
+
+ if (writeflag == VER_READ)
+ goto do_readonly;
+
+ /*
+ * display warning only if -n arg not passed
+ * (otherwise the UI system will take care of it)
+ */
+
+ if (print_warn == 1) {
+ (void) printf(
+ "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device);
+ (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n");
+ (void) printf(" THAT PARTITION OR SLICE.\n");
+ (void) printf("Do you want to continue (y/n)? ");
+
+ rptr = fgets(replybuf, 64*sizeof (char), stdin);
+ if (!rptr || !((replybuf[0] == 'Y') || (replybuf[0] == 'y')))
+ exit(10);
+ }
+
+ for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) {
+ if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error seeking sector %ld Cylinder %ld\n",
+ cursec, cursec / cylsiz);
+ verexit(1);
+ }
+
+ /*
+ * verify sector at a time only when
+ * the whole track write fails;
+ * (if we write a sector at a time, it takes forever)
+ */
+
+ report("Writing", cursec);
+
+ if (write(devfd, verbuf, trksiz) != trksiz) {
+ tmpend = cursec + dkg.dkg_nsect;
+ for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) {
+ /*
+ * try writing to it once; if this fails,
+ * then announce the sector bad on stderr
+ */
+
+ if (lseek
+ (devfd, (long)tmpsec * NBPSCTR, 0) == -1) {
+ (void) fprintf(stderr, "Error seeking "
+ "sector %ld Cylinder %ld\n",
+ tmpsec, cursec / cylsiz);
+ verexit(1);
+ }
+
+ report("Writing", tmpsec);
+
+ if (write(devfd, verbuf, NBPSCTR) != NBPSCTR) {
+ (void) fprintf(stderr,
+ "%ld\n", tmpsec + unix_base);
+ numbadwr++;
+ }
+ }
+ }
+ }
+
+ (void) putchar(eol);
+ do_readonly:
+
+ for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) {
+ if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error seeking sector %ld Cylinder %ld\n",
+ cursec, cursec / cylsiz);
+ verexit(1);
+ }
+
+ /*
+ * read a sector at a time only when
+ * the whole track write fails;
+ * (if we do a sector at a time read, it takes forever)
+ */
+
+ report("Reading", cursec);
+ if (read(devfd, verbuf, trksiz) != trksiz) {
+ tmpend = cursec + dkg.dkg_nsect;
+ for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) {
+ if (lseek(devfd, (long)tmpsec * NBPSCTR, 0)
+ == -1) {
+ (void) fprintf(stderr, "Error seeking"
+ " sector %ld Cylinder %ld\n",
+ tmpsec, cursec / cylsiz);
+ verexit(1);
+ }
+ report("Reading", tmpsec);
+ if (read(devfd, verbuf, NBPSCTR) != NBPSCTR) {
+ (void) fprintf(stderr, "%ld\n",
+ tmpsec + unix_base);
+ numbadrd++;
+ }
+ }
+ }
+ }
+ (void) printf("%c%c======== Diskscan complete ========%c", eol,
+ eol, eol);
+
+ if ((numbadrd > 0) || (numbadwr > 0)) {
+ (void) printf("%cFound %ld bad sector(s) on read,"
+ " %ld bad sector(s) on write%c",
+ eol, numbadrd, numbadwr, eol);
+ }
+}
+
+static void
+verexit(int code)
+{
+ (void) printf("\n");
+ exit(code);
+}
+
+
+/*
+ * report where we are...
+ */
+
+static void
+report(char *what, int sector)
+{
+ (void) printf("%s sector %-7d of %-7ld%c", what, sector,
+ unix_size, eol);
+}