1 /*
2 * Copyright (c) 2011-2022 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <limits.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <getopt.h>
22 #define __STDC_FORMAT_MACROS 1
23 #include <inttypes.h>
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "sg_lib.h"
30 #include "sg_pt.h"
31 #include "sg_cmds_basic.h"
32 #include "sg_cmds_extra.h"
33 #include "sg_unaligned.h"
34 #include "sg_pr2serr.h"
35
36 static const char * version_str = "1.19 20220608";
37
38 #define ME "sg_sanitize: "
39
40 #define SANITIZE_OP 0x48
41 #define SANITIZE_OP_LEN 10
42 #define SANITIZE_SA_OVERWRITE 0x1
43 #define SANITIZE_SA_BLOCK_ERASE 0x2
44 #define SANITIZE_SA_CRYPTO_ERASE 0x3
45 #define SANITIZE_SA_EXIT_FAIL_MODE 0x1f
46 #define DEF_REQS_RESP_LEN 252
47 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
48 #define MAX_XFER_LEN 65535
49 #define EBUFF_SZ 256
50
51 #define SHORT_TIMEOUT 20 /* 20 seconds unless immed=0 ... */
52 #define LONG_TIMEOUT (15 * 3600) /* 15 hours ! */
53 /* Seagate ST32000444SS 2TB disk takes 9.5 hours to format */
54 #define POLL_DURATION_SECS 60
55
56
57 static struct option long_options[] = {
58 {"ause", no_argument, 0, 'A'},
59 {"block", no_argument, 0, 'B'},
60 {"count", required_argument, 0, 'c'},
61 {"crypto", no_argument, 0, 'C'},
62 {"desc", no_argument, 0, 'd'},
63 {"dry-run", no_argument, 0, 'D'},
64 {"dry_run", no_argument, 0, 'D'},
65 {"early", no_argument, 0, 'e'},
66 {"fail", no_argument, 0, 'F'},
67 {"help", no_argument, 0, 'h'},
68 {"invert", no_argument, 0, 'I'},
69 {"ipl", required_argument, 0, 'i'},
70 {"overwrite", no_argument, 0, 'O'},
71 {"pattern", required_argument, 0, 'p'},
72 {"quick", no_argument, 0, 'Q'},
73 {"test", required_argument, 0, 'T'},
74 {"timeout", required_argument, 0, 't'},
75 {"verbose", no_argument, 0, 'v'},
76 {"version", no_argument, 0, 'V'},
77 {"wait", no_argument, 0, 'w'},
78 {"zero", no_argument, 0, 'z'},
79 {0, 0, 0, 0},
80 };
81
82 struct opts_t {
83 bool ause;
84 bool block;
85 bool crypto;
86 bool desc;
87 bool dry_run;
88 bool early;
89 bool fail;
90 bool invert;
91 bool overwrite;
92 bool quick;
93 bool verbose_given;
94 bool version_given;
95 bool wait;
96 bool znr;
97 int count;
98 int ipl; /* initialization pattern length */
99 int test;
100 int timeout; /* in seconds */
101 int verbose;
102 int zero;
103 const char * pattern_fn;
104 };
105
106
107 static void
usage()108 usage()
109 {
110 pr2serr("Usage: sg_sanitize [--ause] [--block] [--count=OC] [--crypto] "
111 "[--dry-run]\n"
112 " [--early] [--fail] [--help] [--invert] "
113 "[--ipl=LEN]\n"
114 " [--overwrite] [--pattern=PF] [--quick] "
115 "[--test=TE]\n"
116 " [--timeout=SECS] [--verbose] [--version] "
117 "[--wait]\n"
118 " [--zero] [--znr] DEVICE\n"
119 " where:\n"
120 " --ause|-A set AUSE bit in cdb\n"
121 " --block|-B do BLOCK ERASE sanitize\n"
122 " --count=OC|-c OC OC is overwrite count field (from 1 "
123 "(def) to 31)\n"
124 " --crypto|-C do CRYPTOGRAPHIC ERASE sanitize\n"
125 " --desc|-d polling request sense sets 'desc' "
126 "field\n"
127 " (def: clear 'desc' field)\n"
128 " --dry-run|-D to preparation but bypass SANITIZE "
129 "command\n"
130 " --early|-e exit once sanitize started (IMMED set "
131 "in cdb)\n"
132 " user can monitor progress with REQUEST "
133 "SENSE\n"
134 " --fail|-F do EXIT FAILURE MODE sanitize\n"
135 " --help|-h print out usage message\n"
136 " --invert|-I set INVERT bit in OVERWRITE parameter "
137 "list\n"
138 " --ipl=LEN|-i LEN initialization pattern length (in "
139 "bytes)\n"
140 " --overwrite|-O do OVERWRITE sanitize\n"
141 " --pattern=PF|-p PF PF is file containing initialization "
142 "pattern\n"
143 " for OVERWRITE\n"
144 " --quick|-Q start sanitize without pause for user\n"
145 " intervention (i.e. no time to "
146 "reconsider)\n"
147 " --test=TE|-T TE TE is placed in TEST field of "
148 "OVERWRITE\n"
149 " parameter list (def: 0)\n"
150 " --timeout=SECS|-t SECS SANITIZE command timeout in "
151 "seconds\n"
152 " --verbose|-v increase verbosity\n"
153 " --version|-V print version string then exit\n"
154 " --wait|-w wait for command to finish (could "
155 "take hours)\n"
156 " --zero|-z use pattern of zeros for "
157 "OVERWRITE\n"
158 " --znr|-Z set ZNR (zone no reset) bit in cdb\n\n"
159 "Performs a SCSI SANITIZE command.\n <<<WARNING>>>: all data "
160 "on DEVICE will be lost.\nDefault action is to give user time to "
161 "reconsider; then execute SANITIZE\ncommand with IMMED bit set; "
162 "then use REQUEST SENSE command every 60\nseconds to poll for a "
163 "progress indication; then exit when there is no\nmore progress "
164 "indication.\n"
165 );
166 }
167
168 /* Invoke SCSI SANITIZE command. Returns 0 if successful, otherwise error */
169 static int
do_sanitize(int sg_fd,const struct opts_t * op,const void * param_lstp,int param_lst_len)170 do_sanitize(int sg_fd, const struct opts_t * op, const void * param_lstp,
171 int param_lst_len)
172 {
173 bool immed;
174 int ret, res, sense_cat, timeout;
175 uint8_t san_cdb[SANITIZE_OP_LEN];
176 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
177 struct sg_pt_base * ptvp;
178
179 if (op->early || op->wait)
180 immed = op->early;
181 else
182 immed = true;
183 timeout = (immed ? SHORT_TIMEOUT : LONG_TIMEOUT);
184 /* only use command line timeout if it exceeds previous defaults */
185 if (op->timeout > timeout)
186 timeout = op->timeout;
187 memset(san_cdb, 0, sizeof(san_cdb));
188 san_cdb[0] = SANITIZE_OP;
189 if (op->overwrite)
190 san_cdb[1] = SANITIZE_SA_OVERWRITE;
191 else if (op->block)
192 san_cdb[1] = SANITIZE_SA_BLOCK_ERASE;
193 else if (op->crypto)
194 san_cdb[1] = SANITIZE_SA_CRYPTO_ERASE;
195 else if (op->fail)
196 san_cdb[1] = SANITIZE_SA_EXIT_FAIL_MODE;
197 else
198 return SG_LIB_SYNTAX_ERROR;
199 if (immed)
200 san_cdb[1] |= 0x80;
201 if (op->znr) /* added sbc4r07 */
202 san_cdb[1] |= 0x40;
203 if (op->ause)
204 san_cdb[1] |= 0x20;
205 sg_put_unaligned_be16((uint16_t)param_lst_len, san_cdb + 7);
206
207 if (op->verbose > 1) {
208 char b[128];
209
210 pr2serr(" Sanitize cdb: %s\n",
211 sg_get_command_str(san_cdb, SANITIZE_OP_LEN, false,
212 sizeof(b), b));
213 if (op->verbose > 2) {
214 if (param_lst_len > 0) {
215 pr2serr(" Parameter list contents:\n");
216 hex2stderr((const uint8_t *)param_lstp, param_lst_len, -1);
217 }
218 pr2serr(" Sanitize command timeout: %d seconds\n", timeout);
219 }
220 }
221 if (op->dry_run) {
222 pr2serr("Due to --dry-run option, bypassing SANITIZE command\n");
223 return 0;
224 }
225 ptvp = construct_scsi_pt_obj();
226 if (NULL == ptvp) {
227 pr2serr("Sanitize: out of memory\n");
228 return -1;
229 }
230 set_scsi_pt_cdb(ptvp, san_cdb, sizeof(san_cdb));
231 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
232 set_scsi_pt_data_out(ptvp, (uint8_t *)param_lstp, param_lst_len);
233 res = do_scsi_pt(ptvp, sg_fd, timeout, op->verbose);
234 ret = sg_cmds_process_resp(ptvp, "Sanitize", res, true /*noisy */,
235 op->verbose, &sense_cat);
236 if (-1 == ret) {
237 if (get_scsi_pt_transport_err(ptvp))
238 ret = SG_LIB_TRANSPORT_ERROR;
239 else
240 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
241 } else if (-2 == ret) {
242 switch (sense_cat) {
243 case SG_LIB_CAT_RECOVERED:
244 case SG_LIB_CAT_NO_SENSE:
245 ret = 0;
246 break;
247 case SG_LIB_CAT_MEDIUM_HARD:
248 {
249 bool valid;
250 int slen;
251 uint64_t ull = 0;
252
253 slen = get_scsi_pt_sense_len(ptvp);
254 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
255 if (valid)
256 pr2serr("Medium or hardware error starting at "
257 "lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull);
258 }
259 ret = sense_cat;
260 break;
261 default:
262 ret = sense_cat;
263 break;
264 }
265 } else {
266 ret = 0;
267 if (op->verbose)
268 pr2serr("Sanitize command %s without error\n",
269 (immed ? "launched" : "completed"));
270 }
271
272 destruct_scsi_pt_obj(ptvp);
273 return ret;
274 }
275
276 #define VPD_DEVICE_ID 0x83
277 #define VPD_ASSOC_LU 0
278 #define VPD_ASSOC_TPORT 1
279 #define TPROTO_ISCSI 5
280
281 static char *
get_lu_name(const uint8_t * bp,int u_len,char * b,int b_len)282 get_lu_name(const uint8_t * bp, int u_len, char * b, int b_len)
283 {
284 int len, off, sns_dlen, dlen, k;
285 uint8_t u_sns[512];
286 char * cp;
287
288 len = u_len - 4;
289 bp += 4;
290 off = -1;
291 if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
292 8 /* SCSI name string (sns) */,
293 3 /* UTF-8 */)) {
294 sns_dlen = bp[off + 3];
295 memcpy(u_sns, bp + off + 4, sns_dlen);
296 /* now want to check if this is iSCSI */
297 off = -1;
298 if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_TPORT,
299 8 /* SCSI name string (sns) */,
300 3 /* UTF-8 */)) {
301 if ((0x80 & bp[1]) && (TPROTO_ISCSI == (bp[0] >> 4))) {
302 snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
303 return b;
304 }
305 }
306 } else
307 sns_dlen = 0;
308 if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
309 3 /* NAA */, 1 /* binary */)) {
310 dlen = bp[off + 3];
311 if (! ((8 == dlen) || (16 ==dlen)))
312 return b;
313 cp = b;
314 for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
315 snprintf(cp, b_len, "%02x", bp[off + 4 + k]);
316 cp += 2;
317 b_len -= 2;
318 }
319 } else if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
320 2 /* EUI */, 1 /* binary */)) {
321 dlen = bp[off + 3];
322 if (! ((8 == dlen) || (12 == dlen) || (16 ==dlen)))
323 return b;
324 cp = b;
325 for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
326 snprintf(cp, b_len, "%02x", bp[off + 4 + k]);
327 cp += 2;
328 b_len -= 2;
329 }
330 } else if (sns_dlen > 0)
331 snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
332 return b;
333 }
334
335 #define SAFE_STD_INQ_RESP_LEN 36
336 #define VPD_SUPPORTED_VPDS 0x0
337 #define VPD_UNIT_SERIAL_NUM 0x80
338 #define VPD_DEVICE_ID 0x83
339
340 static int
print_dev_id(int fd,uint8_t * sinq_resp,int max_rlen,int verbose)341 print_dev_id(int fd, uint8_t * sinq_resp, int max_rlen, int verbose)
342 {
343 int res, k, n, verb, pdt, has_sn, has_di;
344 uint8_t b[256];
345 char a[256];
346 char pdt_name[64];
347
348 verb = (verbose > 1) ? verbose - 1 : 0;
349 memset(sinq_resp, 0, max_rlen);
350 res = sg_ll_inquiry(fd, false, false /* evpd */, 0 /* pg_op */, b,
351 SAFE_STD_INQ_RESP_LEN, 1, verb);
352 if (res)
353 return res;
354 n = b[4] + 5;
355 if (n > SAFE_STD_INQ_RESP_LEN)
356 n = SAFE_STD_INQ_RESP_LEN;
357 memcpy(sinq_resp, b, (n < max_rlen) ? n : max_rlen);
358 if (n == SAFE_STD_INQ_RESP_LEN) {
359 pdt = b[0] & PDT_MASK;
360 printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
361 (const char *)(b + 8), (const char *)(b + 16),
362 (const char *)(b + 32),
363 sg_get_pdt_str(pdt, sizeof(pdt_name), pdt_name), pdt);
364 if (verbose)
365 printf(" PROTECT=%d\n", !!(b[5] & 1));
366 if (b[5] & 1)
367 printf(" << supports protection information>>\n");
368 } else {
369 pr2serr("Short INQUIRY response: %d bytes, expect at least 36\n", n);
370 return SG_LIB_CAT_OTHER;
371 }
372 res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_SUPPORTED_VPDS, b,
373 SAFE_STD_INQ_RESP_LEN, 1, verb);
374 if (res) {
375 if (verbose)
376 pr2serr("VPD_SUPPORTED_VPDS gave res=%d\n", res);
377 return 0;
378 }
379 if (VPD_SUPPORTED_VPDS != b[1]) {
380 if (verbose)
381 pr2serr("VPD_SUPPORTED_VPDS corrupted\n");
382 return 0;
383 }
384 n = sg_get_unaligned_be16(b + 2);
385 if (n > (SAFE_STD_INQ_RESP_LEN - 4))
386 n = (SAFE_STD_INQ_RESP_LEN - 4);
387 for (k = 0, has_sn = 0, has_di = 0; k < n; ++k) {
388 if (VPD_UNIT_SERIAL_NUM == b[4 + k])
389 ++has_sn;
390 else if (VPD_DEVICE_ID == b[4 + k]) {
391 ++has_di;
392 break;
393 }
394 }
395 if (has_sn) {
396 res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_UNIT_SERIAL_NUM,
397 b, sizeof(b), 1, verb);
398 if (res) {
399 if (verbose)
400 pr2serr("VPD_UNIT_SERIAL_NUM gave res=%d\n", res);
401 return 0;
402 }
403 if (VPD_UNIT_SERIAL_NUM != b[1]) {
404 if (verbose)
405 pr2serr("VPD_UNIT_SERIAL_NUM corrupted\n");
406 return 0;
407 }
408 n = sg_get_unaligned_be16(b + 2);
409 if (n > (int)(sizeof(b) - 4))
410 n = (sizeof(b) - 4);
411 printf(" Unit serial number: %.*s\n", n, (const char *)(b + 4));
412 }
413 if (has_di) {
414 res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_DEVICE_ID, b,
415 sizeof(b), 1, verb);
416 if (res) {
417 if (verbose)
418 pr2serr("VPD_DEVICE_ID gave res=%d\n", res);
419 return 0;
420 }
421 if (VPD_DEVICE_ID != b[1]) {
422 if (verbose)
423 pr2serr("VPD_DEVICE_ID corrupted\n");
424 return 0;
425 }
426 n = sg_get_unaligned_be16(b + 2);
427 if (n > (int)(sizeof(b) - 4))
428 n = (sizeof(b) - 4);
429 n = strlen(get_lu_name(b, n + 4, a, sizeof(a)));
430 if (n > 0)
431 printf(" LU name: %.*s\n", n, a);
432 }
433 return 0;
434 }
435
436
437 int
main(int argc,char * argv[])438 main(int argc, char * argv[])
439 {
440 bool got_stdin = false;
441 int k, res, c, infd, progress, vb, n, resp_len, err;
442 int sg_fd = -1;
443 int param_lst_len = 0;
444 int ret = -1;
445 const char * device_name = NULL;
446 char ebuff[EBUFF_SZ];
447 char b[80];
448 uint8_t rsBuff[DEF_REQS_RESP_LEN];
449 uint8_t * wBuff = NULL;
450 uint8_t * free_wBuff = NULL;
451 struct opts_t opts;
452 struct opts_t * op;
453 struct stat a_stat;
454 uint8_t inq_resp[SAFE_STD_INQ_RESP_LEN];
455
456 op = &opts;
457 memset(op, 0, sizeof(opts));
458 op->count = 1;
459 while (1) {
460 int option_index = 0;
461
462 c = getopt_long(argc, argv, "ABc:CdDeFhi:IOp:Qt:T:vVwzZ",
463 long_options, &option_index);
464 if (c == -1)
465 break;
466
467 switch (c) {
468 case 'A':
469 op->ause = true;
470 break;
471 case 'B':
472 op->block = true;
473 break;
474 case 'c':
475 op->count = sg_get_num(optarg);
476 if ((op->count < 1) || (op->count > 31)) {
477 pr2serr("bad argument to '--count', expect 1 to 31\n");
478 return SG_LIB_SYNTAX_ERROR;
479 }
480 break;
481 case 'C':
482 op->crypto = true;
483 break;
484 case 'd':
485 op->desc = true;
486 break;
487 case 'D':
488 op->dry_run = true;
489 break;
490 case 'e':
491 op->early = true;
492 break;
493 case 'F':
494 op->fail = true;
495 break;
496 case 'h':
497 case '?':
498 usage();
499 return 0;
500 case 'i':
501 op->ipl = sg_get_num(optarg);
502 if ((op->ipl < 1) || (op->ipl > 65535)) {
503 pr2serr("bad argument to '--ipl', expect 1 to 65535\n");
504 return SG_LIB_SYNTAX_ERROR;
505 }
506 break;
507 case 'I':
508 op->invert = true;
509 break;
510 case 'O':
511 op->overwrite = true;
512 break;
513 case 'p':
514 op->pattern_fn = optarg;
515 break;
516 case 'Q':
517 op->quick = true;
518 break;
519 case 't':
520 op->timeout = sg_get_num(optarg);
521 if (op->timeout < 0) {
522 pr2serr("bad argument to '--timeout=SECS', want 0 or more\n");
523 return SG_LIB_SYNTAX_ERROR;
524 }
525 break;
526 case 'T':
527 op->test = sg_get_num(optarg);
528 if ((op->test < 0) || (op->test > 3)) {
529 pr2serr("bad argument to '--test', expect 0 to 3\n");
530 return SG_LIB_SYNTAX_ERROR;
531 }
532 break;
533 case 'v':
534 op->verbose_given = true;
535 ++op->verbose;
536 break;
537 case 'V':
538 op->version_given = true;
539 break;
540 case 'w':
541 op->wait = true;
542 break;
543 case 'z':
544 ++op->zero;
545 break;
546 case 'Z':
547 op->znr = true;
548 break;
549 default:
550 pr2serr("unrecognised option code 0x%x ??\n", c);
551 usage();
552 return SG_LIB_SYNTAX_ERROR;
553 }
554 }
555 if (optind < argc) {
556 if (NULL == device_name) {
557 device_name = argv[optind];
558 ++optind;
559 }
560 if (optind < argc) {
561 for (; optind < argc; ++optind)
562 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
563 usage();
564 return SG_LIB_SYNTAX_ERROR;
565 }
566 }
567 #ifdef DEBUG
568 pr2serr("In DEBUG mode, ");
569 if (op->verbose_given && op->version_given) {
570 pr2serr("but override: '-vV' given, zero verbose and continue\n");
571 op->verbose_given = false;
572 op->version_given = false;
573 op->verbose = 0;
574 } else if (! op->verbose_given) {
575 pr2serr("set '-vv'\n");
576 op->verbose = 2;
577 } else
578 pr2serr("keep verbose=%d\n", op->verbose);
579 #else
580 if (op->verbose_given && op->version_given)
581 pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
582 #endif
583 if (op->version_given) {
584 pr2serr(ME "version: %s\n", version_str);
585 return 0;
586 }
587
588 if (NULL == device_name) {
589 pr2serr("Missing device name!\n\n");
590 usage();
591 return SG_LIB_SYNTAX_ERROR;
592 }
593 vb = op->verbose;
594 n = (int)op->block + (int)op->crypto + (int)op->fail + (int)op->overwrite;
595 if (1 != n) {
596 pr2serr("one and only one of '--block', '--crypto', '--fail' or "
597 "'--overwrite' please\n");
598 return SG_LIB_CONTRADICT;
599 }
600 if (op->overwrite) {
601 if (op->zero) {
602 if (op->pattern_fn) {
603 pr2serr("confused: both '--pattern=PF' and '--zero' "
604 "options\n");
605 return SG_LIB_CONTRADICT;
606 }
607 op->ipl = 4;
608 } else {
609 if (NULL == op->pattern_fn) {
610 pr2serr("'--overwrite' requires '--pattern=PF' or '--zero' "
611 "option\n");
612 return SG_LIB_CONTRADICT;
613 }
614 got_stdin = (0 == strcmp(op->pattern_fn, "-"));
615 if (! got_stdin) {
616 memset(&a_stat, 0, sizeof(a_stat));
617 if (stat(op->pattern_fn, &a_stat) < 0) {
618 err = errno;
619 pr2serr("pattern file: unable to stat(%s): %s\n",
620 op->pattern_fn, safe_strerror(err));
621 ret = sg_convert_errno(err);
622 goto err_out;
623 }
624 if (op->ipl <= 0) {
625 op->ipl = (int)a_stat.st_size;
626 if (op->ipl > MAX_XFER_LEN) {
627 pr2serr("pattern file length exceeds 65535 bytes, "
628 "need '--ipl=LEN' option\n");
629 return SG_LIB_FILE_ERROR;
630 }
631 }
632 }
633 if (op->ipl < 1) {
634 pr2serr("'--overwrite' requires '--ipl=LEN' option if can't "
635 "get PF length\n");
636 return SG_LIB_CONTRADICT;
637 }
638 }
639 }
640
641 sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb);
642 if (sg_fd < 0) {
643 if (op->verbose)
644 pr2serr(ME "open error: %s: %s\n", device_name,
645 safe_strerror(-sg_fd));
646 ret = sg_convert_errno(-sg_fd);
647 goto err_out;
648 }
649
650 ret = print_dev_id(sg_fd, inq_resp, sizeof(inq_resp), op->verbose);
651 if (ret)
652 goto err_out;
653
654 if (op->overwrite) {
655 param_lst_len = op->ipl + 4;
656 wBuff = (uint8_t*)sg_memalign(op->ipl + 4, 0, &free_wBuff, false);
657 if (NULL == wBuff) {
658 pr2serr("unable to allocate %d bytes of memory with calloc()\n",
659 op->ipl + 4);
660 ret = sg_convert_errno(ENOMEM);
661 goto err_out;
662 }
663 if (op->zero) {
664 if (2 == op->zero) /* treat -zz as fill with 0xff bytes */
665 memset(wBuff + 4, 0xff, op->ipl);
666 else
667 memset(wBuff + 4, 0, op->ipl);
668 } else {
669 if (got_stdin) {
670 infd = STDIN_FILENO;
671 if (sg_set_binary_mode(STDIN_FILENO) < 0)
672 perror("sg_set_binary_mode");
673 } else {
674 if ((infd = open(op->pattern_fn, O_RDONLY)) < 0) {
675 err = errno;
676 snprintf(ebuff, EBUFF_SZ, ME "could not open %s for "
677 "reading", op->pattern_fn);
678 perror(ebuff);
679 ret = sg_convert_errno(err);
680 goto err_out;
681 } else if (sg_set_binary_mode(infd) < 0)
682 perror("sg_set_binary_mode");
683 }
684 res = read(infd, wBuff + 4, op->ipl);
685 if (res < 0) {
686 err = errno;
687 snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
688 op->pattern_fn);
689 perror(ebuff);
690 if (! got_stdin)
691 close(infd);
692 ret = sg_convert_errno(err);
693 goto err_out;
694 }
695 if (res < op->ipl) {
696 pr2serr("tried to read %d bytes from %s, got %d bytes\n",
697 op->ipl, op->pattern_fn, res);
698 pr2serr(" so pad with 0x0 bytes and continue\n");
699 }
700 if (! got_stdin)
701 close(infd);
702 }
703 wBuff[0] = op->count & 0x1f;
704 if (op->test)
705 wBuff[0] |= ((op->test & 0x3) << 5);
706 if (op->invert)
707 wBuff[0] |= 0x80;
708 sg_put_unaligned_be16((uint16_t)op->ipl, wBuff + 2);
709 }
710
711 if ((! op->quick) && (! op->fail))
712 sg_warn_and_wait("SANITIZE", device_name, true);
713
714 ret = do_sanitize(sg_fd, op, wBuff, param_lst_len);
715 if (ret) {
716 sg_get_category_sense_str(ret, sizeof(b), b, vb);
717 pr2serr("Sanitize failed: %s\n", b);
718 }
719
720 if ((0 == ret) && (! op->early) && (! op->wait)) {
721 for (k = 0; ;++k) { /* unbounded, exits via break */
722 if (op->dry_run && (k > 0)) {
723 pr2serr("Due to --dry-run option, leave poll loop\n");
724 break;
725 }
726 sg_sleep_secs(POLL_DURATION_SECS);
727 memset(rsBuff, 0x0, sizeof(rsBuff));
728 res = sg_ll_request_sense(sg_fd, op->desc, rsBuff, sizeof(rsBuff),
729 1, vb);
730 if (res) {
731 ret = res;
732 if (SG_LIB_CAT_INVALID_OP == res)
733 pr2serr("Request Sense command not supported\n");
734 else if (SG_LIB_CAT_ILLEGAL_REQ == res) {
735 pr2serr("bad field in Request Sense cdb\n");
736 if (op->desc) {
737 pr2serr("Descriptor type sense may not be supported, "
738 "try again with fixed type\n");
739 op->desc = false;
740 continue;
741 }
742 } else {
743 sg_get_category_sense_str(res, sizeof(b), b, vb);
744 pr2serr("Request Sense: %s\n", b);
745 if (0 == vb)
746 pr2serr(" try the '-v' option for more "
747 "information\n");
748 }
749 break;
750 }
751 /* "Additional sense length" same in descriptor and fixed */
752 resp_len = rsBuff[7] + 8;
753 if (vb > 2) {
754 pr2serr("Parameter data in hex\n");
755 hex2stderr(rsBuff, resp_len, -1);
756 }
757 progress = -1;
758 sg_get_sense_progress_fld(rsBuff, resp_len, &progress);
759 if (progress < 0) {
760 ret = res;
761 if (vb > 1)
762 pr2serr("No progress indication found, iteration %d\n",
763 k + 1);
764 if ((0 == k) && vb)
765 pr2serr("Sanitize seems to be successful and finished "
766 "quickly\n");
767 /* N.B. exits first time there isn't a progress indication */
768 break;
769 } else
770 printf("Progress indication: %d%% done\n",
771 (progress * 100) / 65536);
772 }
773 }
774
775 err_out:
776 if (free_wBuff)
777 free(free_wBuff);
778 if (sg_fd >= 0) {
779 res = sg_cmds_close_device(sg_fd);
780 if (res < 0) {
781 pr2serr("close error: %s\n", safe_strerror(-res));
782 if (0 == ret)
783 ret = sg_convert_errno(-res);
784 }
785 }
786 if (0 == op->verbose) {
787 if (! sg_if_can2stderr("sg_sanitize failed: ", ret))
788 pr2serr("Some error occurred, try again with '-v' "
789 "or '-vv' for more information\n");
790 }
791 return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
792 }
793