xref: /aosp_15_r20/external/sg3_utils/src/sg_verify.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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