aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2014-09-23 15:01:28 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2014-09-23 15:01:28 +0000
commitc9095aa14eac1d52c4232da68db91cdaf5c6575f (patch)
treecaa72029af32d5631c11ff2910b6defff1b81f96
parent3bb7224c7cc629054f3d1b1a1ea5d85433c620f4 (diff)
downloadsg3_utils-c9095aa14eac1d52c4232da68db91cdaf5c6575f.tar.gz
sg_sanitize: add --desc and --zero options
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@609 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog3
-rw-r--r--doc/sg_sanitize.858
-rw-r--r--src/sg_sanitize.c145
3 files changed, 130 insertions, 76 deletions
diff --git a/ChangeLog b/ChangeLog
index aa3560ff..e1f82cbb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.40 [20140821] [svn: r608]
+Changelog for sg3_utils-1.40 [20140923] [svn: r609]
- sg_write_verify: new utility for WRITE AND VERIFY
- sg_senddiag: add --maxlen= option
- sg_copy_results: correct response length calculations
@@ -18,6 +18,7 @@ Changelog for sg3_utils-1.40 [20140821] [svn: r608]
trailing NULL
- add --warn option mainly for broken joins
- add optional descriptions to -ee output
+ - sg_sanitize: add --desc and --zero options
- sg_logs: refine tape drive output
- sg_raw: with -vvv decode T10 CDB name
- sg_opcodes: add --compact field
diff --git a/doc/sg_sanitize.8 b/doc/sg_sanitize.8
index 0e86bb90..2ba0b5d5 100644
--- a/doc/sg_sanitize.8
+++ b/doc/sg_sanitize.8
@@ -1,13 +1,14 @@
-.TH SG_SANITIZE "8" "September 2013" "sg3_utils\-1.37" SG3_UTILS
+.TH SG_SANITIZE "8" "September 2014" "sg3_utils\-1.40" SG3_UTILS
.SH NAME
sg_sanitize \- remove all user data from disk with SCSI SANITIZE command
.SH SYNOPSIS
.B sg_sanitize
[\fI\-\-ause\fR] [\fI\-\-block\fR] [\fI\-\-count=OC\fR] [\fI\-\-crypto\fR]
-[\fI\-\-early\fR] [\fI\-\-fail\fR] [\fI\-\-help\fR] [\fI\-\-invert\fR]
-[\fI\-\-ipl=LEN\fR] [\fI\-\-overwrite\fR] [\fI\-\-pattern=PF\fR]
-[\fI\-\-quick\fR] [\fI\-\-test=TE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
-[\fI\-\-wait\fR] \fIDEVICE\fR
+[\fI\-\-desc\fR] [\fI\-\-early\fR] [\fI\-\-fail\fR] [\fI\-\-help\fR]
+[\fI\-\-invert\fR] [\fI\-\-ipl=LEN\fR] [\fI\-\-overwrite\fR]
+[\fI\-\-pattern=PF\fR] [\fI\-\-quick\fR] [\fI\-\-test=TE\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wait\fR] [\fI\-\-zero\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -32,7 +33,7 @@ the \fI\-\-quick\fR option is given in which case the sanitize operation
starts immediately. The disk's INQUIRY response strings are printed out just
in case the wrong \fIDEVICE\fR has been given.
.PP
-If the \fI\-\-early\fR option is given this utility will exit soon
+If the \fI\-\-early\fR option is given then this utility will exit soon
after starting the SANITIZE command with the IMMED bit set. The user can
monitor the progress of the sanitize operation with
the "sg_request \-\-num=9999 \-\-progress" which sends a REQUEST SENSE
@@ -51,7 +52,7 @@ option name.
.TP
\fB\-A\fR, \fB\-\-ause\fR
sets the AUSE bit in the cdb. AUSE is an acronym for "allow unrestricted
-sanitize exit". Default action is to leave the bit cleared.
+sanitize exit". The default action is to leave the AUSE bit cleared.
.TP
\fB\-B\fR, \fB\-\-block\fR
perform a "block erase" sanitize operation.
@@ -64,11 +65,19 @@ the default.
\fB\-C\fR, \fB\-\-crypto\fR
perform a "cryptographic erase" sanitize operation.
.TP
+\fB\-d\fR, \fB\-\-desc\fR
+sets the DESC field in the REQUEST SENSE command used for polling. By
+default this field is set to zero. A REQUEST SENSE polling loop is
+used after the SANITIZE command is issued (assuming that neither the
+\fI\-\-early\fR nor the \fI\-\-wait\fR option have been given) to check
+on the progress of this command as it can take some time.
+.TP
\fB\-e\fR, \fB\-\-early\fR
the default action of this utility is to poll the disk every 60 seconds to
fetch the progress indication until the sanitize is finished. When this
-option is given this utility will exit "early" as soon as the sanitize
-has commenced. This option and \fI\-\-wait\fR cannot both be given.
+option is given this utility will exit "early" as soon as the SANITIZE
+command with the IMMED bit set to 1 has been acknowledged. This option and
+\fI\-\-wait\fR cannot both be given.
.TP
\fB\-F\fR, \fB\-\-fail\fR
perform an "exit failure mode" sanitize operation. Typically requires the
@@ -79,10 +88,11 @@ print out the usage information then exit.
.TP
\fB\-i\fR, \fB\-\-ipl\fR=\fILEN\fR
set the initialization pattern length to \fILEN\fR bytes. By default it is
-set to the length of the pattern file (\fIPF\fR). Only active when the
-\fI\-\-overwrite\fR option is also given. It is the number of bytes from
-the \fIPF\fR file that will be used as the initialization pattern. The
-minimum size is 1 byte and the maximum is the logical block size of the
+set to the length of the pattern file (\fIPF\fR) or 4 if the \fI\-\-zero\fR
+option is given. Only active when the \fI\-\-overwrite\fR option is also
+given. It is the number of bytes from the \fIPF\fR file that will be used
+as the initialization pattern (if the \fI\-\-zero\fR option is not given).
+The minimum size is 1 byte and the maximum is the logical block size of the
\fIDEVICE\fR (and not to exceed 65535). If \fILEN\fR exceeds the \fIPF\fR
file size then the initialization pattern is padded with zeros.
.TP
@@ -93,8 +103,8 @@ INVERT bit. When the INVERT bit is set then the initialization pattern
is inverted between consecutive overwrite passes.
.TP
\fB\-O\fR, \fB\-\-overwrite\fR
-perform an "overwrite" sanitize operation. When this option is given
-then the \fI\-\-pattern=PF\fR option is required.
+perform an "overwrite" sanitize operation. When this option is given then
+the \fI\-\-pattern=PF\fR or the \fI\-\-zero\fR option is required.
.TP
\fB\-p\fR, \fB\-\-pattern\fR=\fIPF\fR
where \fIPF\fR is the filename of a file containing the initialization
@@ -128,12 +138,24 @@ operation is complete (or fails). When this option is given (and the
\fI\-\-early\fR option is not given) then the SANITIZE command is started
with the IMMED bit clear. For a large disk this might take hours. [A
cryptographic erase operation could potentially be very quick.]
+.TP
+\fB\-z\fR, \fB\-\-zero\fR
+with an "overwrite" sanitize operation this option causes the initialization
+pattern to be zero (4 zeros are used as the initialization pattern). Cannot
+be used with the \fI\-\-pattern=PF\fR option. If this option is given
+twice (e.g. '\-zz') then 0xff is used as the initialization byte.
.SH NOTES
The SCSI SANITIZE command is closely related to the ATA SANITIZE command,
both are relatively new with the ATA command being the first one defined.
The SCSI to ATA Translation (SAT) definition for the SCSI SANITIZE command
appeared in the SAT\-3 revision 4 draft.
.PP
+When a SAT layer is used to a (S)ATA disk then for OVERWRITE the
+initialization pattern must be 4 bytes long. So this means either the
+\fI\-\-zero\fR option may be given, or a pattern file (with the
+\fI\-\-pattern=PF\fR option) that is 4 bytes long or set to that
+length with the \fI\-\-ipl=LEN\fR option.
+.PP
The SCSI SANITIZE command is related to the SCSI FORMAT UNIT command. It
is likely that a block erase sanitize operation would take a similar
amount of time as a format on the same disk (e.g. 9 hours for a 2 Terabyte
@@ -183,7 +205,7 @@ If the 15 second reconsideration time is not required add the
.PP
sg_sanitize \-\-block \-\-quick \-\-early /dev/sdm
.PP
-To do an "overwrite" sanitize a pattern file is required:
+To do an "overwrite" sanitize a pattern file may be given:
.PP
sg_sanitize \-\-overwrite \-\-pattern=rand.img /dev/sdm
.PP
@@ -193,6 +215,8 @@ sanitize operation:
.PP
sg_sanitize \-\-overwrite \-\-pattern=rand.img \-\-ipl=17 /dev/sdm
.PP
+To overwrite with zeros use:
+ sg_sanitize \-\-overwrite \-\-zero /dev/sdm
.SH EXIT STATUS
The exit status of sg_sanitize is 0 when it is successful. Otherwise see
the sg3_utils(8) man page. Unless the \fI\-\-wait\fR option is given, the
@@ -202,7 +226,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2011\-2013 Douglas Gilbert
+Copyright \(co 2011\-2014 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/src/sg_sanitize.c b/src/sg_sanitize.c
index a21cb7b6..30522b76 100644
--- a/src/sg_sanitize.c
+++ b/src/sg_sanitize.c
@@ -26,7 +26,7 @@
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-static const char * version_str = "0.94 20140516";
+static const char * version_str = "0.95 20140923";
/* Not all environments support the Unix sleep() */
#if defined(MSC_VER) || defined(__MINGW32__)
@@ -64,6 +64,7 @@ static struct option long_options[] = {
{"block", no_argument, 0, 'B'},
{"count", required_argument, 0, 'c'},
{"crypto", no_argument, 0, 'C'},
+ {"desc", no_argument, 0, 'd'},
{"early", no_argument, 0, 'e'},
{"fail", no_argument, 0, 'F'},
{"help", no_argument, 0, 'h'},
@@ -76,6 +77,7 @@ static struct option long_options[] = {
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"wait", no_argument, 0, 'w'},
+ {"zero", no_argument, 0, 'z'},
{0, 0, 0, 0},
};
@@ -84,6 +86,7 @@ struct opts_t {
int block;
int count;
int crypto;
+ int desc;
int early;
int fail;
int invert;
@@ -93,6 +96,7 @@ struct opts_t {
int quick;
int verbose;
int wait;
+ int zero;
const char * pattern_fn;
};
@@ -114,6 +118,9 @@ usage()
" --count=OC|-c OC OC is overwrite count field (from 1 "
"(def) to 31)\n"
" --crypto|-C do CRYPTOGRAPHIC ERASE sanitize\n"
+ " --desc|-d polling request sense sets 'desc' "
+ "field\n"
+ " (def: clear 'desc' field)\n"
" --early|-e exit once sanitize started (IMMED set "
"in cdb)\n"
" user can monitor progress with REQUEST "
@@ -137,9 +144,11 @@ usage()
" --verbose|-v increase verbosity\n"
" --version|-V print version string then exit\n"
" --wait|-w wait for command to finish (could "
- "take hours)\n\n"
+ "take hours)\n"
+ " --zero|-z use pattern of zeros for "
+ "OVERWRITE\n\n"
"Performs a SCSI SANITIZE command.\n <<<WARNING>>>: all data "
- "on DEVICE will lost.\nDefault action is to give user time to "
+ "on DEVICE will be lost.\nDefault action is to give user time to "
"reconsider; then execute SANITIZE\ncommand with IMMED bit set; "
"then use REQUEST SENSE command every 60\nseconds to poll for a "
"progress indication; then exit when there is no\nmore progress "
@@ -238,7 +247,7 @@ do_sanitize(int sg_fd, const struct opts_t * op, const void * param_lstp,
int
main(int argc, char * argv[])
{
- int sg_fd, k, res, c, infd, progress, vb, n, desc, resp_len;
+ int sg_fd, k, res, c, infd, progress, vb, n, resp_len;
int got_stdin = 0;
int param_lst_len = 0;
const char * device_name = NULL;
@@ -259,7 +268,7 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "ABc:CeFhi:IOp:QT:vVw", long_options,
+ c = getopt_long(argc, argv, "ABc:CdeFhi:IOp:QT:vVwz", long_options,
&option_index);
if (c == -1)
break;
@@ -282,6 +291,9 @@ main(int argc, char * argv[])
case 'C':
++op->crypto;
break;
+ case 'd':
+ ++op->desc;
+ break;
case 'e':
++op->early;
break;
@@ -328,6 +340,9 @@ main(int argc, char * argv[])
case 'w':
++op->wait;
break;
+ case 'z':
+ ++op->zero;
+ break;
default:
fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
usage();
@@ -360,34 +375,42 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
if (op->overwrite) {
- if (NULL == op->pattern_fn) {
- fprintf(stderr, "'--overwrite' requires '--pattern=PF' "
- "option\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- got_stdin = (0 == strcmp(op->pattern_fn, "-")) ? 1 : 0;
- if (! got_stdin) {
- memset(&a_stat, 0, sizeof(a_stat));
- if (stat(op->pattern_fn, &a_stat) < 0) {
- fprintf(stderr, "pattern file: unable to stat(%s): %s\n",
- op->pattern_fn, safe_strerror(errno));
- return SG_LIB_FILE_ERROR;
+ if (op->zero) {
+ if (op->pattern_fn) {
+ fprintf(stderr, "confused: both '--pattern=PF' and '--zero' "
+ "options\n");
+ return SG_LIB_SYNTAX_ERROR;
}
- if (op->ipl <= 0) {
- op->ipl = (int)a_stat.st_size;
- if (op->ipl > MAX_XFER_LEN) {
- fprintf(stderr, "pattern file length exceeds 65535 "
- "bytes, need '--ipl=LEN' option\n");
- return SG_LIB_FILE_ERROR;
+ op->ipl = 4;
+ } else {
+ if (NULL == op->pattern_fn) {
+ fprintf(stderr, "'--overwrite' requires '--pattern=PF' "
+ "or '--zero' option\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ got_stdin = (0 == strcmp(op->pattern_fn, "-")) ? 1 : 0;
+ if (! got_stdin) {
+ memset(&a_stat, 0, sizeof(a_stat));
+ if (stat(op->pattern_fn, &a_stat) < 0) {
+ fprintf(stderr, "pattern file: unable to stat(%s): %s\n",
+ op->pattern_fn, safe_strerror(errno));
+ return SG_LIB_FILE_ERROR;
+ }
+ if (op->ipl <= 0) {
+ op->ipl = (int)a_stat.st_size;
+ if (op->ipl > MAX_XFER_LEN) {
+ fprintf(stderr, "pattern file length exceeds 65535 "
+ "bytes, need '--ipl=LEN' option\n");
+ return SG_LIB_FILE_ERROR;
+ }
}
}
+ if (op->ipl < 1) {
+ fprintf(stderr, "'--overwrite' requires '--ipl=LEN' "
+ "option if can't get PF length\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
}
- if (op->ipl < 1) {
- fprintf(stderr, "'--overwrite' requires '--ipl=LEN' "
- "option if can't get PF length\n");
- return SG_LIB_SYNTAX_ERROR;
- }
-
}
sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, vb);
@@ -419,38 +442,44 @@ main(int argc, char * argv[])
ret = SG_LIB_SYNTAX_ERROR;
goto err_out;
}
- if (got_stdin) {
- infd = STDIN_FILENO;
- if (sg_set_binary_mode(STDIN_FILENO) < 0)
- perror("sg_set_binary_mode");
+ if (op->zero) {
+ if (2 == op->zero) /* treat -zz as fill with 0xff bytes */
+ memset(wBuff + 4, 0xff, op->ipl);
+ else
+ memset(wBuff + 4, 0, op->ipl);
} else {
- if ((infd = open(op->pattern_fn, O_RDONLY)) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- ME "could not open %s for reading", op->pattern_fn);
+ if (got_stdin) {
+ infd = STDIN_FILENO;
+ if (sg_set_binary_mode(STDIN_FILENO) < 0)
+ perror("sg_set_binary_mode");
+ } else {
+ if ((infd = open(op->pattern_fn, O_RDONLY)) < 0) {
+ snprintf(ebuff, EBUFF_SZ, ME "could not open %s for "
+ "reading", op->pattern_fn);
+ perror(ebuff);
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ } else if (sg_set_binary_mode(infd) < 0)
+ perror("sg_set_binary_mode");
+ }
+ res = read(infd, wBuff + 4, op->ipl);
+ if (res < 0) {
+ snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
+ op->pattern_fn);
perror(ebuff);
+ if (! got_stdin)
+ close(infd);
ret = SG_LIB_FILE_ERROR;
goto err_out;
- } else if (sg_set_binary_mode(infd) < 0)
- perror("sg_set_binary_mode");
- }
- res = read(infd, wBuff + 4, op->ipl);
- if (res < 0) {
- snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
- op->pattern_fn);
- perror(ebuff);
+ }
+ if (res < op->ipl) {
+ fprintf(stderr, "tried to read %d bytes from %s, got %d "
+ "bytes\n", op->ipl, op->pattern_fn, res);
+ fprintf(stderr, " so pad with 0x0 bytes and continue\n");
+ }
if (! got_stdin)
close(infd);
- ret = SG_LIB_FILE_ERROR;
- goto err_out;
}
- if (res < op->ipl) {
- fprintf(stderr, "tried to read %d bytes from %s, got %d "
- "bytes\n", op->ipl, op->pattern_fn, res);
- fprintf(stderr, " so pad with 0x0 bytes and continue\n");
- }
- if (! got_stdin)
- close(infd);
-
wBuff[0] = op->count & 0x1f;;
if (op->test)
wBuff[0] |= ((op->test & 0x3) << 5);
@@ -482,10 +511,10 @@ main(int argc, char * argv[])
}
if ((0 == ret) && (0 == op->early) && (0 == op->wait)) {
- for (k = 0, desc = 1 ;; ++k) {
+ for (k = 0 ;; ++k) {
sleep_for(POLL_DURATION_SECS);
memset(requestSenseBuff, 0x0, sizeof(requestSenseBuff));
- res = sg_ll_request_sense(sg_fd, desc, requestSenseBuff,
+ res = sg_ll_request_sense(sg_fd, op->desc, requestSenseBuff,
sizeof(requestSenseBuff), 1, vb);
if (res) {
ret = res;
@@ -493,10 +522,10 @@ main(int argc, char * argv[])
fprintf(stderr, "Request Sense command not supported\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res) {
fprintf(stderr, "bad field in Request Sense cdb\n");
- if (1 == desc) {
+ if (1 == op->desc) {
fprintf(stderr, "Descriptor type sense may not be "
"supported, try again with fixed type\n");
- desc = 0;
+ op->desc = 0;
continue;
}
} else {