1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * Copyright (c) 2004-2020 Douglas Gilbert.
3*44704f69SBart Van Assche * All rights reserved.
4*44704f69SBart Van Assche * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche *
7*44704f69SBart Van Assche * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche */
9*44704f69SBart Van Assche
10*44704f69SBart Van Assche #include <unistd.h>
11*44704f69SBart Van Assche #include <fcntl.h>
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stdarg.h>
15*44704f69SBart Van Assche #include <stdbool.h>
16*44704f69SBart Van Assche #include <errno.h>
17*44704f69SBart Van Assche #include <string.h>
18*44704f69SBart Van Assche #include <getopt.h>
19*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
20*44704f69SBart Van Assche #include <inttypes.h>
21*44704f69SBart Van Assche
22*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
23*44704f69SBart Van Assche #include "config.h"
24*44704f69SBart Van Assche #endif
25*44704f69SBart Van Assche #include "sg_lib.h"
26*44704f69SBart Van Assche #include "sg_cmds_basic.h"
27*44704f69SBart Van Assche #include "sg_cmds_extra.h"
28*44704f69SBart Van Assche #include "sg_pr2serr.h"
29*44704f69SBart Van Assche
30*44704f69SBart Van Assche /* A utility program for the Linux OS SCSI subsystem.
31*44704f69SBart Van Assche *
32*44704f69SBart Van Assche * This program issues the SCSI VERIFY(10) or VERIFY(16) command to the given
33*44704f69SBart Van Assche * SCSI block device.
34*44704f69SBart Van Assche *
35*44704f69SBart Van Assche * N.B. This utility should, but doesn't, check the logical block size with
36*44704f69SBart Van Assche * the SCSI READ CAPACITY command. It is up to the user to make sure that
37*44704f69SBart Van Assche * the count of blocks requested and the number of bytes transferred (when
38*44704f69SBart Van Assche * BYTCHK>0) are "in sync". That caclculation is somewhat complicated by
39*44704f69SBart Van Assche * the possibility of protection data (DIF).
40*44704f69SBart Van Assche */
41*44704f69SBart Van Assche
42*44704f69SBart Van Assche static const char * version_str = "1.27 20201029"; /* sbc4r17 */
43*44704f69SBart Van Assche
44*44704f69SBart Van Assche #define ME "sg_verify: "
45*44704f69SBart Van Assche
46*44704f69SBart Van Assche #define EBUFF_SZ 256
47*44704f69SBart Van Assche
48*44704f69SBart Van Assche
49*44704f69SBart Van Assche static struct option long_options[] = {
50*44704f69SBart Van Assche {"0", no_argument, 0, '0'},
51*44704f69SBart Van Assche {"16", no_argument, 0, 'S'},
52*44704f69SBart Van Assche {"bpc", required_argument, 0, 'b'},
53*44704f69SBart Van Assche {"bytchk", required_argument, 0, 'B'}, /* 4 backward compatibility */
54*44704f69SBart Van Assche {"count", required_argument, 0, 'c'},
55*44704f69SBart Van Assche {"dpo", no_argument, 0, 'd'},
56*44704f69SBart Van Assche {"ebytchk", required_argument, 0, 'E'}, /* extended bytchk (2 bits) */
57*44704f69SBart Van Assche {"group", required_argument, 0, 'g'},
58*44704f69SBart Van Assche {"help", no_argument, 0, 'h'},
59*44704f69SBart Van Assche {"in", required_argument, 0, 'i'},
60*44704f69SBart Van Assche {"lba", required_argument, 0, 'l'},
61*44704f69SBart Van Assche {"nbo", required_argument, 0, 'n'}, /* misspelling, legacy */
62*44704f69SBart Van Assche {"ndo", required_argument, 0, 'n'},
63*44704f69SBart Van Assche {"quiet", no_argument, 0, 'q'},
64*44704f69SBart Van Assche {"readonly", no_argument, 0, 'r'},
65*44704f69SBart Van Assche {"verbose", no_argument, 0, 'v'},
66*44704f69SBart Van Assche {"version", no_argument, 0, 'V'},
67*44704f69SBart Van Assche {"vrprotect", required_argument, 0, 'P'},
68*44704f69SBart Van Assche {0, 0, 0, 0},
69*44704f69SBart Van Assche };
70*44704f69SBart Van Assche
71*44704f69SBart Van Assche static void
usage()72*44704f69SBart Van Assche usage()
73*44704f69SBart Van Assche {
74*44704f69SBart Van Assche pr2serr("Usage: sg_verify [--0] [--16] [--bpc=BPC] [--count=COUNT] "
75*44704f69SBart Van Assche "[--dpo]\n"
76*44704f69SBart Van Assche " [--ebytchk=BCH] [--ff] [--group=GN] [--help] "
77*44704f69SBart Van Assche "[--in=IF]\n"
78*44704f69SBart Van Assche " [--lba=LBA] [--ndo=NDO] [--quiet] "
79*44704f69SBart Van Assche "[--readonly]\n"
80*44704f69SBart Van Assche " [--verbose] [--version] [--vrprotect=VRP] "
81*44704f69SBart Van Assche "DEVICE\n"
82*44704f69SBart Van Assche " where:\n"
83*44704f69SBart Van Assche " --0|-0 fill buffer with zeros (don't read "
84*44704f69SBart Van Assche "stdin)\n"
85*44704f69SBart Van Assche " --16|-S use VERIFY(16) (def: use "
86*44704f69SBart Van Assche "VERIFY(10) )\n"
87*44704f69SBart Van Assche " --bpc=BPC|-b BPC max blocks per verify command "
88*44704f69SBart Van Assche "(def: 128)\n"
89*44704f69SBart Van Assche " --count=COUNT|-c COUNT count of blocks to verify "
90*44704f69SBart Van Assche "(def: 1).\n"
91*44704f69SBart Van Assche " --dpo|-d disable page out (cache retention "
92*44704f69SBart Van Assche "priority)\n"
93*44704f69SBart Van Assche " --ebytchk=BCH|-E BCH sets BYTCHK value, either 1, 2 "
94*44704f69SBart Van Assche "or 3 (def: 0).\n"
95*44704f69SBart Van Assche " BCH overrides BYTCHK=1 set by "
96*44704f69SBart Van Assche "'--ndo='. If\n"
97*44704f69SBart Van Assche " BCH is 3 then NDO must be the LBA "
98*44704f69SBart Van Assche "size\n"
99*44704f69SBart Van Assche " (plus protection size if DIF "
100*44704f69SBart Van Assche "active)\n"
101*44704f69SBart Van Assche " --ff|-f fill buffer with 0xff bytes (don't read "
102*44704f69SBart Van Assche "stdin)\n"
103*44704f69SBart Van Assche " --group=GN|-g GN set group number field to GN (def: 0)\n"
104*44704f69SBart Van Assche " --help|-h print out usage message\n"
105*44704f69SBart Van Assche " --in=IF|-i IF input from file called IF (def: "
106*44704f69SBart Van Assche "stdin)\n"
107*44704f69SBart Van Assche " only active if --ebytchk=BCH given\n"
108*44704f69SBart Van Assche " --lba=LBA|-l LBA logical block address to start "
109*44704f69SBart Van Assche "verify (def: 0)\n"
110*44704f69SBart Van Assche " --ndo=NDO|-n NDO NDO is number of bytes placed in "
111*44704f69SBart Van Assche "data-out buffer.\n"
112*44704f69SBart Van Assche " These are fetched from IF (or "
113*44704f69SBart Van Assche "stdin) and used\n"
114*44704f69SBart Van Assche " to verify the device data against. "
115*44704f69SBart Van Assche "Forces\n"
116*44704f69SBart Van Assche " --bpc=COUNT. Sets BYTCHK (byte check) "
117*44704f69SBart Van Assche "to 1\n"
118*44704f69SBart Van Assche " --quiet|-q suppress miscompare report to stderr, "
119*44704f69SBart Van Assche "still\n"
120*44704f69SBart Van Assche " causes an exit status of 14\n"
121*44704f69SBart Van Assche " --readonly|-r open DEVICE read-only (def: open it "
122*44704f69SBart Van Assche "read-write)\n"
123*44704f69SBart Van Assche " --verbose|-v increase verbosity\n"
124*44704f69SBart Van Assche " --version|-V print version string and exit\n"
125*44704f69SBart Van Assche " --vrprotect=VRP|-P VRP set vrprotect field to VRP "
126*44704f69SBart Van Assche "(def: 0)\n\n"
127*44704f69SBart Van Assche "Performs one or more SCSI VERIFY(10) or SCSI VERIFY(16) "
128*44704f69SBart Van Assche "commands. sbc3r34\nmade the BYTCHK field two bits wide "
129*44704f69SBart Van Assche "(it was a single bit).\n");
130*44704f69SBart Van Assche }
131*44704f69SBart Van Assche
132*44704f69SBart Van Assche int
main(int argc,char * argv[])133*44704f69SBart Van Assche main(int argc, char * argv[])
134*44704f69SBart Van Assche {
135*44704f69SBart Van Assche bool bpc_given = false;
136*44704f69SBart Van Assche bool dpo = false;
137*44704f69SBart Van Assche bool ff_given = false;
138*44704f69SBart Van Assche bool got_stdin = false;
139*44704f69SBart Van Assche bool quiet = false;
140*44704f69SBart Van Assche bool readonly = false;
141*44704f69SBart Van Assche bool verbose_given = false;
142*44704f69SBart Van Assche bool verify16 = false;
143*44704f69SBart Van Assche bool version_given = false;
144*44704f69SBart Van Assche bool zero_given = false;
145*44704f69SBart Van Assche int res, c, num, nread, infd;
146*44704f69SBart Van Assche int sg_fd = -1;
147*44704f69SBart Van Assche int bpc = 128;
148*44704f69SBart Van Assche int group = 0;
149*44704f69SBart Van Assche int bytchk = 0;
150*44704f69SBart Van Assche int ndo = 0; /* number of bytes in data-out buffer */
151*44704f69SBart Van Assche int verbose = 0;
152*44704f69SBart Van Assche int ret = 0;
153*44704f69SBart Van Assche int vrprotect = 0;
154*44704f69SBart Van Assche unsigned int info = 0;
155*44704f69SBart Van Assche int64_t count = 1;
156*44704f69SBart Van Assche int64_t ll;
157*44704f69SBart Van Assche int64_t orig_count;
158*44704f69SBart Van Assche uint64_t info64 = 0;
159*44704f69SBart Van Assche uint64_t lba = 0;
160*44704f69SBart Van Assche uint64_t orig_lba;
161*44704f69SBart Van Assche uint8_t * ref_data = NULL;
162*44704f69SBart Van Assche uint8_t * free_ref_data = NULL;
163*44704f69SBart Van Assche const char * device_name = NULL;
164*44704f69SBart Van Assche const char * file_name = NULL;
165*44704f69SBart Van Assche const char * vc;
166*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
167*44704f69SBart Van Assche
168*44704f69SBart Van Assche while (1) {
169*44704f69SBart Van Assche int option_index = 0;
170*44704f69SBart Van Assche
171*44704f69SBart Van Assche c = getopt_long(argc, argv, "0b:B:c:dE:fg:hi:l:n:P:qrSvV",
172*44704f69SBart Van Assche long_options, &option_index);
173*44704f69SBart Van Assche if (c == -1)
174*44704f69SBart Van Assche break;
175*44704f69SBart Van Assche
176*44704f69SBart Van Assche switch (c) {
177*44704f69SBart Van Assche case '0':
178*44704f69SBart Van Assche zero_given = true;
179*44704f69SBart Van Assche break;
180*44704f69SBart Van Assche case 'b':
181*44704f69SBart Van Assche bpc = sg_get_num(optarg);
182*44704f69SBart Van Assche if (bpc < 1) {
183*44704f69SBart Van Assche pr2serr("bad argument to '--bpc'\n");
184*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
185*44704f69SBart Van Assche }
186*44704f69SBart Van Assche bpc_given = true;
187*44704f69SBart Van Assche break;
188*44704f69SBart Van Assche case 'c':
189*44704f69SBart Van Assche count = sg_get_llnum(optarg);
190*44704f69SBart Van Assche if (count < 0) {
191*44704f69SBart Van Assche pr2serr("bad argument to '--count'\n");
192*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
193*44704f69SBart Van Assche }
194*44704f69SBart Van Assche break;
195*44704f69SBart Van Assche case 'd':
196*44704f69SBart Van Assche dpo = true;
197*44704f69SBart Van Assche break;
198*44704f69SBart Van Assche case 'E':
199*44704f69SBart Van Assche bytchk = sg_get_num(optarg);
200*44704f69SBart Van Assche if ((bytchk < 0) || (bytchk > 3)) {
201*44704f69SBart Van Assche pr2serr("bad argument to '--ebytchk'\n");
202*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
203*44704f69SBart Van Assche }
204*44704f69SBart Van Assche break;
205*44704f69SBart Van Assche case 'f':
206*44704f69SBart Van Assche ff_given = true;
207*44704f69SBart Van Assche break;
208*44704f69SBart Van Assche case 'g':
209*44704f69SBart Van Assche group = sg_get_num(optarg);
210*44704f69SBart Van Assche if ((group < 0) || (group > 63)) {
211*44704f69SBart Van Assche pr2serr("bad argument to '--group'\n");
212*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
213*44704f69SBart Van Assche }
214*44704f69SBart Van Assche break;
215*44704f69SBart Van Assche case 'h':
216*44704f69SBart Van Assche case '?':
217*44704f69SBart Van Assche usage();
218*44704f69SBart Van Assche return 0;
219*44704f69SBart Van Assche case 'i':
220*44704f69SBart Van Assche file_name = optarg;
221*44704f69SBart Van Assche break;
222*44704f69SBart Van Assche case 'l':
223*44704f69SBart Van Assche ll = sg_get_llnum(optarg);
224*44704f69SBart Van Assche if (-1 == ll) {
225*44704f69SBart Van Assche pr2serr("bad argument to '--lba'\n");
226*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
227*44704f69SBart Van Assche }
228*44704f69SBart Van Assche lba = (uint64_t)ll;
229*44704f69SBart Van Assche break;
230*44704f69SBart Van Assche case 'n': /* number of bytes in data-out buffer */
231*44704f69SBart Van Assche case 'B': /* undocumented, old --bytchk=NDO option */
232*44704f69SBart Van Assche ndo = sg_get_num(optarg);
233*44704f69SBart Van Assche if (ndo < 1) {
234*44704f69SBart Van Assche pr2serr("bad argument to '--ndo'\n");
235*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
236*44704f69SBart Van Assche }
237*44704f69SBart Van Assche break;
238*44704f69SBart Van Assche case 'P':
239*44704f69SBart Van Assche vrprotect = sg_get_num(optarg);
240*44704f69SBart Van Assche if (-1 == vrprotect) {
241*44704f69SBart Van Assche pr2serr("bad argument to '--vrprotect'\n");
242*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
243*44704f69SBart Van Assche }
244*44704f69SBart Van Assche if ((vrprotect < 0) || (vrprotect > 7)) {
245*44704f69SBart Van Assche pr2serr("'--vrprotect' requires a value from 0 to 7 "
246*44704f69SBart Van Assche "(inclusive)\n");
247*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
248*44704f69SBart Van Assche }
249*44704f69SBart Van Assche break;
250*44704f69SBart Van Assche case 'q':
251*44704f69SBart Van Assche quiet = true;
252*44704f69SBart Van Assche break;
253*44704f69SBart Van Assche case 'r':
254*44704f69SBart Van Assche readonly = true;
255*44704f69SBart Van Assche break;
256*44704f69SBart Van Assche case 'S':
257*44704f69SBart Van Assche verify16 = true;
258*44704f69SBart Van Assche break;
259*44704f69SBart Van Assche case 'v':
260*44704f69SBart Van Assche verbose_given = true;
261*44704f69SBart Van Assche ++verbose;
262*44704f69SBart Van Assche break;
263*44704f69SBart Van Assche case 'V':
264*44704f69SBart Van Assche version_given = true;
265*44704f69SBart Van Assche break;
266*44704f69SBart Van Assche default:
267*44704f69SBart Van Assche pr2serr("unrecognised option code 0x%x ??\n", c);
268*44704f69SBart Van Assche usage();
269*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
270*44704f69SBart Van Assche }
271*44704f69SBart Van Assche }
272*44704f69SBart Van Assche if (optind < argc) {
273*44704f69SBart Van Assche if (NULL == device_name) {
274*44704f69SBart Van Assche device_name = argv[optind];
275*44704f69SBart Van Assche ++optind;
276*44704f69SBart Van Assche }
277*44704f69SBart Van Assche if (optind < argc) {
278*44704f69SBart Van Assche for (; optind < argc; ++optind)
279*44704f69SBart Van Assche pr2serr("Unexpected extra argument: %s\n", argv[optind]);
280*44704f69SBart Van Assche usage();
281*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
282*44704f69SBart Van Assche }
283*44704f69SBart Van Assche }
284*44704f69SBart Van Assche #ifdef DEBUG
285*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
286*44704f69SBart Van Assche if (verbose_given && version_given) {
287*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and continue\n");
288*44704f69SBart Van Assche verbose_given = false;
289*44704f69SBart Van Assche version_given = false;
290*44704f69SBart Van Assche verbose = 0;
291*44704f69SBart Van Assche } else if (! verbose_given) {
292*44704f69SBart Van Assche pr2serr("set '-vv'\n");
293*44704f69SBart Van Assche verbose = 2;
294*44704f69SBart Van Assche } else
295*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", verbose);
296*44704f69SBart Van Assche #else
297*44704f69SBart Van Assche if (verbose_given && version_given)
298*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
299*44704f69SBart Van Assche #endif
300*44704f69SBart Van Assche if (version_given) {
301*44704f69SBart Van Assche pr2serr(ME "version: %s\n", version_str);
302*44704f69SBart Van Assche return 0;
303*44704f69SBart Van Assche }
304*44704f69SBart Van Assche
305*44704f69SBart Van Assche if (ndo > 0) {
306*44704f69SBart Van Assche if (0 == bytchk)
307*44704f69SBart Van Assche bytchk = 1;
308*44704f69SBart Van Assche if (bpc_given && (bpc != count))
309*44704f69SBart Van Assche pr2serr("'bpc' argument ignored, using --bpc=%" PRIu64 "\n",
310*44704f69SBart Van Assche count);
311*44704f69SBart Van Assche if (count > 0x7fffffffLL) {
312*44704f69SBart Van Assche pr2serr("count exceed 31 bits, way too large\n");
313*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
314*44704f69SBart Van Assche }
315*44704f69SBart Van Assche #if 0
316*44704f69SBart Van Assche if ((3 == bytchk) && (1 != count)) {
317*44704f69SBart Van Assche pr2serr("count must be 1 when bytchk=3\n");
318*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
319*44704f69SBart Van Assche }
320*44704f69SBart Van Assche // bpc = (int)count;
321*44704f69SBart Van Assche #endif
322*44704f69SBart Van Assche } else if (bytchk > 0) {
323*44704f69SBart Van Assche pr2serr("when the 'ebytchk=BCH' option is given, then '--ndo=NDO' "
324*44704f69SBart Van Assche "must also be given\n");
325*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
326*44704f69SBart Van Assche }
327*44704f69SBart Van Assche if ((zero_given || ff_given) && file_name) {
328*44704f69SBart Van Assche pr2serr("giving --0 or --ff is not compatible with --if=%s\n",
329*44704f69SBart Van Assche file_name);
330*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
331*44704f69SBart Van Assche }
332*44704f69SBart Van Assche
333*44704f69SBart Van Assche if ((bpc > 0xffff) && (! verify16)) {
334*44704f69SBart Van Assche pr2serr("'%s' exceeds 65535, so use VERIFY(16)\n",
335*44704f69SBart Van Assche (ndo > 0) ? "count" : "bpc");
336*44704f69SBart Van Assche verify16 = true;
337*44704f69SBart Van Assche }
338*44704f69SBart Van Assche if (((lba + count - 1) > 0xffffffffLLU) && (! verify16)) {
339*44704f69SBart Van Assche pr2serr("'lba' exceed 32 bits, so use VERIFY(16)\n");
340*44704f69SBart Van Assche verify16 = true;
341*44704f69SBart Van Assche }
342*44704f69SBart Van Assche if ((group > 0) && (! verify16))
343*44704f69SBart Van Assche pr2serr("group number ignored with VERIFY(10) command, use the --16 "
344*44704f69SBart Van Assche "option\n");
345*44704f69SBart Van Assche
346*44704f69SBart Van Assche orig_count = count;
347*44704f69SBart Van Assche orig_lba = lba;
348*44704f69SBart Van Assche
349*44704f69SBart Van Assche if (ndo > 0) {
350*44704f69SBart Van Assche ref_data = (uint8_t *)sg_memalign(ndo, 0, &free_ref_data, verbose > 4);
351*44704f69SBart Van Assche if (NULL == ref_data) {
352*44704f69SBart Van Assche pr2serr("failed to allocate %d byte buffer\n", ndo);
353*44704f69SBart Van Assche ret = sg_convert_errno(ENOMEM);
354*44704f69SBart Van Assche goto err_out;
355*44704f69SBart Van Assche }
356*44704f69SBart Van Assche if (ff_given)
357*44704f69SBart Van Assche memset(ref_data, 0xff, ndo);
358*44704f69SBart Van Assche if (zero_given || ff_given)
359*44704f69SBart Van Assche goto skip;
360*44704f69SBart Van Assche if ((NULL == file_name) || (0 == strcmp(file_name, "-"))) {
361*44704f69SBart Van Assche got_stdin = true;
362*44704f69SBart Van Assche infd = STDIN_FILENO;
363*44704f69SBart Van Assche if (sg_set_binary_mode(STDIN_FILENO) < 0)
364*44704f69SBart Van Assche perror("sg_set_binary_mode");
365*44704f69SBart Van Assche } else {
366*44704f69SBart Van Assche if ((infd = open(file_name, O_RDONLY)) < 0) {
367*44704f69SBart Van Assche ret = sg_convert_errno(errno);
368*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
369*44704f69SBart Van Assche ME "could not open %s for reading", file_name);
370*44704f69SBart Van Assche perror(ebuff);
371*44704f69SBart Van Assche goto err_out;
372*44704f69SBart Van Assche } else if (sg_set_binary_mode(infd) < 0)
373*44704f69SBart Van Assche perror("sg_set_binary_mode");
374*44704f69SBart Van Assche }
375*44704f69SBart Van Assche if (verbose && got_stdin)
376*44704f69SBart Van Assche pr2serr("about to wait on STDIN\n");
377*44704f69SBart Van Assche for (nread = 0; nread < ndo; nread += res) {
378*44704f69SBart Van Assche res = read(infd, ref_data + nread, ndo - nread);
379*44704f69SBart Van Assche if (res <= 0) {
380*44704f69SBart Van Assche ret = sg_convert_errno(errno);
381*44704f69SBart Van Assche pr2serr("reading from %s failed at file offset=%d\n",
382*44704f69SBart Van Assche (got_stdin ? "stdin" : file_name), nread);
383*44704f69SBart Van Assche goto err_out;
384*44704f69SBart Van Assche }
385*44704f69SBart Van Assche }
386*44704f69SBart Van Assche if (! got_stdin)
387*44704f69SBart Van Assche close(infd);
388*44704f69SBart Van Assche }
389*44704f69SBart Van Assche skip:
390*44704f69SBart Van Assche if (NULL == device_name) {
391*44704f69SBart Van Assche pr2serr("missing device name!\n\n");
392*44704f69SBart Van Assche usage();
393*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
394*44704f69SBart Van Assche goto err_out;
395*44704f69SBart Van Assche }
396*44704f69SBart Van Assche sg_fd = sg_cmds_open_device(device_name, readonly, verbose);
397*44704f69SBart Van Assche if (sg_fd < 0) {
398*44704f69SBart Van Assche if (verbose)
399*44704f69SBart Van Assche pr2serr(ME "open error: %s: %s\n", device_name,
400*44704f69SBart Van Assche safe_strerror(-sg_fd));
401*44704f69SBart Van Assche ret = sg_convert_errno(-sg_fd);
402*44704f69SBart Van Assche goto err_out;
403*44704f69SBart Van Assche }
404*44704f69SBart Van Assche
405*44704f69SBart Van Assche vc = verify16 ? "VERIFY(16)" : "VERIFY(10)";
406*44704f69SBart Van Assche for (; count > 0; count -= bpc, lba += bpc) {
407*44704f69SBart Van Assche num = (count > bpc) ? bpc : count;
408*44704f69SBart Van Assche if (verify16)
409*44704f69SBart Van Assche res = sg_ll_verify16(sg_fd, vrprotect, dpo, bytchk,
410*44704f69SBart Van Assche lba, num, group, ref_data,
411*44704f69SBart Van Assche ndo, &info64, !quiet , verbose);
412*44704f69SBart Van Assche else
413*44704f69SBart Van Assche res = sg_ll_verify10(sg_fd, vrprotect, dpo, bytchk,
414*44704f69SBart Van Assche (unsigned int)lba, num, ref_data,
415*44704f69SBart Van Assche ndo, &info, !quiet, verbose);
416*44704f69SBart Van Assche if (0 != res) {
417*44704f69SBart Van Assche char b[80];
418*44704f69SBart Van Assche
419*44704f69SBart Van Assche ret = res;
420*44704f69SBart Van Assche switch (res) {
421*44704f69SBart Van Assche case SG_LIB_CAT_ILLEGAL_REQ:
422*44704f69SBart Van Assche pr2serr("bad field in %s cdb, near lba=0x%" PRIx64 "\n", vc,
423*44704f69SBart Van Assche lba);
424*44704f69SBart Van Assche break;
425*44704f69SBart Van Assche case SG_LIB_CAT_MEDIUM_HARD:
426*44704f69SBart Van Assche pr2serr("%s medium or hardware error near lba=0x%" PRIx64 "\n",
427*44704f69SBart Van Assche vc, lba);
428*44704f69SBart Van Assche break;
429*44704f69SBart Van Assche case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO:
430*44704f69SBart Van Assche if (verify16)
431*44704f69SBart Van Assche pr2serr("%s medium or hardware error, reported lba=0x%"
432*44704f69SBart Van Assche PRIx64 "\n", vc, info64);
433*44704f69SBart Van Assche else
434*44704f69SBart Van Assche pr2serr("%s medium or hardware error, reported lba=0x%x\n",
435*44704f69SBart Van Assche vc, info);
436*44704f69SBart Van Assche break;
437*44704f69SBart Van Assche case SG_LIB_CAT_MISCOMPARE:
438*44704f69SBart Van Assche if ((0 == quiet) || verbose)
439*44704f69SBart Van Assche pr2serr("%s MISCOMPARE: started at LBA 0x%" PRIx64 "\n",
440*44704f69SBart Van Assche vc, lba);
441*44704f69SBart Van Assche break;
442*44704f69SBart Van Assche default:
443*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, verbose);
444*44704f69SBart Van Assche pr2serr("%s: %s\n", vc, b);
445*44704f69SBart Van Assche pr2serr(" failed near lba=%" PRIu64 " [0x%" PRIx64 "]\n",
446*44704f69SBart Van Assche lba, lba);
447*44704f69SBart Van Assche break;
448*44704f69SBart Van Assche }
449*44704f69SBart Van Assche break;
450*44704f69SBart Van Assche }
451*44704f69SBart Van Assche }
452*44704f69SBart Van Assche
453*44704f69SBart Van Assche if (verbose && (0 == ret) && (orig_count > 1))
454*44704f69SBart Van Assche pr2serr("Verified %" PRId64 " [0x%" PRIx64 "] blocks from lba %" PRIu64
455*44704f69SBart Van Assche " [0x%" PRIx64 "]\n without error\n", orig_count,
456*44704f69SBart Van Assche (uint64_t)orig_count, orig_lba, orig_lba);
457*44704f69SBart Van Assche
458*44704f69SBart Van Assche err_out:
459*44704f69SBart Van Assche if (sg_fd >= 0) {
460*44704f69SBart Van Assche res = sg_cmds_close_device(sg_fd);
461*44704f69SBart Van Assche if (res < 0) {
462*44704f69SBart Van Assche pr2serr("close error: %s\n", safe_strerror(-res));
463*44704f69SBart Van Assche if (0 == ret)
464*44704f69SBart Van Assche ret = sg_convert_errno(-res);
465*44704f69SBart Van Assche }
466*44704f69SBart Van Assche }
467*44704f69SBart Van Assche if (free_ref_data)
468*44704f69SBart Van Assche free(free_ref_data);
469*44704f69SBart Van Assche if (0 == verbose) {
470*44704f69SBart Van Assche if (! sg_if_can2stderr("sg_verify failed: ", ret))
471*44704f69SBart Van Assche pr2serr("Some error occurred, try again with '-v' "
472*44704f69SBart Van Assche "or '-vv' for more information\n");
473*44704f69SBart Van Assche }
474*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
475*44704f69SBart Van Assche }
476