1 /*
2 * Copyright (c) 2013-2014 Douglas Gilbert.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 /*
31 * This file contains some common functions for ddpt.
32 */
33
34 /* Was needed for posix_fadvise() */
35 /* #define _XOPEN_SOURCE 600 */
36
37 /* Need _GNU_SOURCE for O_DIRECT */
38 #ifndef _GNU_SOURCE
39 #define _GNU_SOURCE
40 #endif
41
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #define __STDC_LIMIT_MACROS 1 /* for UINT64_MAX, UINT32_MAX, etc */
50 #include <limits.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <fcntl.h>
54 #define __STDC_FORMAT_MACROS 1
55 #include <inttypes.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58
59 /* N.B. config.h must precede anything that depends on HAVE_* */
60 #ifdef HAVE_CONFIG_H
61 #include "config.h"
62 #endif
63
64 #ifdef HAVE_NANOSLEEP
65 #include <time.h>
66 #endif
67
68 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
69 #include <time.h>
70 #elif defined(HAVE_GETTIMEOFDAY)
71 #include <time.h>
72 #include <sys/time.h>
73 #endif
74
75 #include "ddpt.h" /* includes <signal.h> */
76
77 #ifdef SG_LIB_LINUX
78 #include <sys/ioctl.h>
79 #include <sys/sysmacros.h>
80 #include <sys/file.h>
81 #include <linux/major.h>
82 #include <linux/fs.h> /* <sys/mount.h> */
83 #include <linux/mtio.h> /* For tape ioctls */
84 #ifndef MTWEOFI
85 #define MTWEOFI 35 /* write an end-of-file record (mark) in immediate mode */
86 #endif
87
88 #ifdef HAVE_FALLOCATE
89 #include <linux/falloc.h>
90 #ifndef FALLOC_FL_KEEP_SIZE
91 #define FALLOC_FL_KEEP_SIZE 0x01 /* from lk 3.1 linux/falloc.h */
92 #endif
93 #endif
94
95 #endif /* SG_LIB_LINUX */
96
97 #ifdef SG_LIB_FREEBSD
98 #include <sys/ioctl.h>
99 #include <libgen.h>
100 #ifdef __DragonFly__
101 #include <sys/diskslice.h>
102 #else
103 #include <sys/disk.h>
104 #endif
105 #include <sys/filio.h>
106 #endif
107
108 #ifdef SG_LIB_SOLARIS
109 #include <sys/ioctl.h>
110 #include <sys/dkio.h>
111 #endif
112
113 #ifdef SG_LIB_WIN32
114 #ifndef SG_LIB_MINGW
115 /* cygwin */
116 #include <sys/ioctl.h>
117 #endif
118
119 #endif /* end SG_LIB_WIN32 */
120
121 #include "sg_lib.h"
122
123
124 static const char * errblk_file = "errblk.txt";
125
126
127 /* Want safe, 'n += snprintf(b + n, blen - n, ...)' style sequence of
128 * functions. Returns number number of chars placed in cp excluding the
129 * trailing null char. So for cp_max_len > 0 the return value is always
130 * < cp_max_len; for cp_max_len <= 1 the return value is 0 and no chars
131 * are written to cp. Note this means that when cp_max_len = 1, this
132 * function assumes that cp[0] is the null character and does nothing
133 * (and returns 0). */
134 static int
my_snprintf(char * cp,int cp_max_len,const char * fmt,...)135 my_snprintf(char * cp, int cp_max_len, const char * fmt, ...)
136 {
137 va_list args;
138 int n;
139
140 if (cp_max_len < 2)
141 return 0;
142 va_start(args, fmt);
143 n = vsnprintf(cp, cp_max_len, fmt, args);
144 va_end(args);
145 return (n < cp_max_len) ? n : (cp_max_len - 1);
146 }
147
148 /* Abbreviation of fprintf(stderr, ...) */
149 int /* Global function */
pr2serr(const char * fmt,...)150 pr2serr(const char * fmt, ...)
151 {
152 va_list args;
153 int n;
154
155 va_start(args, fmt);
156 n = vfprintf(stderr, fmt, args);
157 va_end(args);
158 return n;
159 }
160
161 void
sleep_ms(int millisecs)162 sleep_ms(int millisecs)
163 {
164 #ifdef SG_LIB_WIN32
165 win32_sleep_ms(millisecs);
166 #elif defined(HAVE_NANOSLEEP)
167 struct timespec request;
168
169 if (millisecs > 0) {
170 request.tv_sec = millisecs / 1000;
171 request.tv_nsec = (millisecs % 1000) * 1000000;
172 if ((nanosleep(&request, NULL) < 0) && (EINTR != errno))
173 perror("nanosleep");
174 }
175 #endif
176 }
177
178 void
state_init(struct opts_t * op,struct flags_t * ifp,struct flags_t * ofp,struct dev_info_t * idip,struct dev_info_t * odip,struct dev_info_t * o2dip)179 state_init(struct opts_t * op, struct flags_t * ifp, struct flags_t * ofp,
180 struct dev_info_t * idip, struct dev_info_t * odip,
181 struct dev_info_t * o2dip)
182 {
183 memset(op, 0, sizeof(struct opts_t));
184 op->dd_count = -1;
185 op->highest_unrecovered = -1;
186 op->do_time = 1; /* default was 0 in sg_dd */
187 op->id_usage = -1;
188 op->list_id = 1;
189 op->prio = 1;
190 op->max_uas = MAX_UNIT_ATTENTIONS;
191 op->max_aborted = MAX_ABORTED_CMDS;
192 memset(ifp, 0, sizeof(struct flags_t));
193 memset(ofp, 0, sizeof(struct flags_t));
194 op->iflagp = ifp;
195 op->oflagp = ofp;
196 memset(idip, 0, sizeof(struct dev_info_t));
197 memset(odip, 0, sizeof(struct dev_info_t));
198 memset(o2dip, 0, sizeof(struct dev_info_t));
199 idip->d_type = FT_OTHER;
200 idip->fd = -1;
201 odip->d_type = FT_OTHER;
202 odip->fd = -1;
203 o2dip->d_type = FT_OTHER;
204 o2dip->fd = -1;
205 op->idip = idip;
206 op->odip = odip;
207 op->o2dip = o2dip;
208 ifp->cdbsz = DEF_SCSI_CDBSZ;
209 ofp->cdbsz = DEF_SCSI_CDBSZ;
210 #ifdef HAVE_POSIX_FADVISE
211 op->lowest_skip = -1;
212 op->lowest_seek = -1;
213 #endif
214 op->idip->pdt = -1;
215 op->odip->pdt = -1;
216 op->rtf_fd = -1;
217 }
218
219 /* When who<=0 print both in+out, when who==1 print in, else print out */
220 void
print_stats(const char * str,struct opts_t * op,int who)221 print_stats(const char * str, struct opts_t * op, int who)
222 {
223 #ifdef SG_LIB_LINUX
224 /* Print tape read summary if necessary . */
225 print_tape_summary(op, 0, str);
226 #endif
227
228 if ((op->dd_count > 0) && (! op->reading_fifo)) {
229 pr2serr(" remaining block count=%" PRId64, op->dd_count);
230 if ((who < 2) && (op->in_full <= op->dd_count_start) &&
231 (op->dd_count_start >= 4196)) {
232 /* with ints will overflow around 8 TB for bs=1 */
233 int num = (int)((op->in_full * 100) / 4196);
234 int den = (int)(op->dd_count_start / 4196); /* will be >= 1 */
235 int percent;
236
237 percent = num / den;
238 if ((100 == percent) && (op->in_full < op->dd_count_start))
239 --percent; /* don't want rounding to 100 % */
240 pr2serr(" %d%% completed\n", percent);
241 } else
242 pr2serr("\n");
243 }
244 if (who < 2)
245 pr2serr("%s%" PRId64 "+%d records in\n", str, op->in_full,
246 op->in_partial);
247 if (1 != who)
248 pr2serr("%s%" PRId64 "+%d records out\n", str, op->out_full,
249 op->out_partial);
250 if (op->out_sparse_active || op->out_sparing_active) {
251 if (op->out_trim_active) {
252 const char * cp;
253
254 cp = op->trim_errs ? "attempted trim" : "trimmed";
255 if (op->out_sparse_partial > 0)
256 pr2serr("%s%" PRId64 "+%d %s records out\n", str,
257 op->out_sparse, op->out_sparse_partial, cp);
258 else
259 pr2serr("%s%" PRId64 " %s records out\n", str,
260 op->out_sparse, cp);
261 } else if (op->out_sparse_partial > 0)
262 pr2serr("%s%" PRId64 "+%d bypassed records out\n", str,
263 op->out_sparse, op->out_sparse_partial);
264 else
265 pr2serr("%s%" PRId64 " bypassed records out\n", str,
266 op->out_sparse);
267 }
268 if (op->recovered_errs > 0)
269 pr2serr("%s%d recovered read errors\n", str, op->recovered_errs);
270 if (op->num_retries > 0)
271 pr2serr("%s%d retries attempted\n", str, op->num_retries);
272 if (op->unrecovered_errs > 0)
273 pr2serr("%s%d unrecovered read error%s\n", str, op->unrecovered_errs,
274 ((1 == op->unrecovered_errs) ? "" : "s"));
275 if (op->unrecovered_errs && (op->highest_unrecovered >= 0))
276 pr2serr("lowest unrecovered read lba=%" PRId64 ", highest "
277 "unrecovered lba=%" PRId64 "\n", op->lowest_unrecovered,
278 op->highest_unrecovered);
279 if (op->wr_recovered_errs > 0)
280 pr2serr("%s%d recovered write errors\n", str, op->wr_recovered_errs);
281 if (op->wr_unrecovered_errs > 0)
282 pr2serr("%s%d unrecovered write error%s\n", str,
283 op->wr_unrecovered_errs,
284 ((1 == op->wr_unrecovered_errs) ? "" : "s"));
285 if (op->trim_errs)
286 pr2serr("%s%d trim errors\n", str, op->trim_errs);
287 if (op->interrupted_retries > 0)
288 pr2serr("%s%d %s after interrupted system call(s)\n",
289 str, op->interrupted_retries,
290 ((1 == op->interrupted_retries) ? "retry" : "retries"));
291 if (op->has_xcopy)
292 pr2serr("%s%" PRId64 " xcopy command%s done\n", str, op->num_xcopy,
293 ((1 == op->num_xcopy) ? "" : "s"));
294 }
295
296 /* Attempt to categorize the file type from the given filename.
297 * Separate version for Windows and Unix. Windows version does some
298 * file name processing. */
299 #ifndef SG_LIB_WIN32
300
301 #ifdef SG_LIB_LINUX
302 static int bsg_major_checked = 0;
303 static int bsg_major = 0;
304
305 /* In Linux search /proc/devices for bsg character driver in order to
306 * find its major device number since it is allocated dynamically. */
307 static void
find_bsg_major(int verbose)308 find_bsg_major(int verbose)
309 {
310 const char * proc_devices = "/proc/devices";
311 FILE *fp;
312 char a[128];
313 char b[128];
314 char * cp;
315 int n;
316
317 if (NULL == (fp = fopen(proc_devices, "r"))) {
318 if (verbose)
319 pr2serr("fopen %s failed: %s\n", proc_devices,
320 strerror(errno));
321 return;
322 }
323 while ((cp = fgets(b, sizeof(b), fp))) {
324 if ((1 == sscanf(b, "%126s", a)) &&
325 (0 == memcmp(a, "Character", 9)))
326 break;
327 }
328 while (cp && (cp = fgets(b, sizeof(b), fp))) {
329 if (2 == sscanf(b, "%d %126s", &n, a)) {
330 if (0 == strcmp("bsg", a)) {
331 bsg_major = n;
332 break;
333 }
334 } else
335 break;
336 }
337 if (verbose > 5) {
338 if (cp)
339 pr2serr("found bsg_major=%d\n", bsg_major);
340 else
341 pr2serr("found no bsg char device in %s\n", proc_devices);
342 }
343 fclose(fp);
344 }
345 #endif
346
347 /* Categorize file by using the stat() system call on its filename.
348 * If not found FT_ERROR returned. The FT_* constants are a bit mask
349 * and later logic can combine them (e.g. FT_BLOCK | FT_PT).
350 */
351 static int
unix_dd_filetype(const char * filename,int verbose)352 unix_dd_filetype(const char * filename, int verbose)
353 {
354 struct stat st;
355 size_t len = strlen(filename);
356
357 if (verbose) { ; } /* suppress warning */
358 if ((1 == len) && ('.' == filename[0]))
359 return FT_DEV_NULL;
360 if (stat(filename, &st) < 0)
361 return FT_ERROR;
362 if (S_ISREG(st.st_mode)) {
363 // pr2serr("dd_filetype: regular file, st_size=%" PRId64 "\n",
364 // st.st_size);
365 return FT_REG;
366 } else if (S_ISCHR(st.st_mode)) {
367 #ifdef SG_LIB_LINUX
368 /* major() and minor() defined in sys/sysmacros.h */
369 if ((MEM_MAJOR == major(st.st_rdev)) &&
370 (DEV_NULL_MINOR_NUM == minor(st.st_rdev)))
371 return FT_DEV_NULL;
372 if (SCSI_GENERIC_MAJOR == major(st.st_rdev))
373 return FT_PT;
374 if (SCSI_TAPE_MAJOR == major(st.st_rdev))
375 return FT_TAPE;
376 if (! bsg_major_checked) {
377 bsg_major_checked = 1;
378 find_bsg_major(verbose);
379 }
380 if (bsg_major == (int)major(st.st_rdev))
381 return FT_PT;
382 return FT_CHAR; /* assume something like /dev/zero */
383 #elif SG_LIB_FREEBSD
384 {
385 /* int d_flags; for FIOFTYPE ioctl see sys/filio.h */
386 char s[STR_SZ];
387 char * bname;
388
389 strcpy(s, filename);
390 bname = basename(s);
391 if (0 == strcmp("null", bname))
392 return FT_DEV_NULL;
393 else if (0 == memcmp("pass", bname, 4))
394 return FT_PT;
395 else if (0 == memcmp("sa", bname, 2))
396 return FT_TAPE;
397 else
398 return FT_BLOCK; /* freebsd doesn't have block devices! */
399 }
400 #elif SG_LIB_SOLARIS
401 /* might be /dev/rdsk or /dev/scsi , require pt override */
402 return FT_BLOCK;
403 #else
404 return FT_PT;
405 #endif
406 } else if (S_ISBLK(st.st_mode))
407 return FT_BLOCK;
408 else if (S_ISFIFO(st.st_mode))
409 return FT_FIFO;
410 return FT_OTHER;
411 }
412 #endif /* if not SG_LIB_WIN32 */
413
414 /* Categorize file by using the stat() system call on its filename.
415 * If not found FT_ERROR returned. The FT_* constants are a bit mask
416 * and later logic can combine them (e.g. FT_BLOCK | FT_PT).
417 */
418 int
dd_filetype(const char * filename,int verbose)419 dd_filetype(const char * filename, int verbose)
420 {
421 #ifdef SG_LIB_WIN32
422 return win32_dd_filetype(filename, verbose);
423 #else
424 return unix_dd_filetype(filename, verbose);
425 #endif
426 }
427
428 char *
dd_filetype_str(int ft,char * buff,int max_bufflen,const char * fname)429 dd_filetype_str(int ft, char * buff, int max_bufflen, const char * fname)
430 {
431 int off = 0;
432
433 if (FT_DEV_NULL & ft)
434 off += my_snprintf(buff + off, max_bufflen - off, "null device ");
435 if (FT_PT & ft)
436 off += my_snprintf(buff + off, max_bufflen - off,
437 "pass-through [pt] device ");
438 if (FT_TAPE & ft)
439 off += my_snprintf(buff + off, max_bufflen - off, "SCSI tape device ");
440 if (FT_BLOCK & ft)
441 off += my_snprintf(buff + off, max_bufflen - off, "block device ");
442 if (FT_FIFO & ft)
443 off += my_snprintf(buff + off, max_bufflen - off,
444 "fifo [stdin, stdout, named pipe] ");
445 if (FT_REG & ft)
446 off += my_snprintf(buff + off, max_bufflen - off, "regular file ");
447 if (FT_CHAR & ft)
448 off += my_snprintf(buff + off, max_bufflen - off, "char device ");
449 if (FT_OTHER & ft)
450 off += my_snprintf(buff + off, max_bufflen - off, "other file type ");
451 if (FT_ERROR & ft)
452 off += my_snprintf(buff + off, max_bufflen - off,
453 "unable to 'stat' %s ", (fname ? fname : "file"));
454 return buff;
455 }
456
457 #ifdef SG_LIB_LINUX
458 static int
lin_get_blkdev_capacity(struct opts_t * op,int which_arg,int64_t * num_blks,int * blk_sz)459 lin_get_blkdev_capacity(struct opts_t * op, int which_arg, int64_t * num_blks,
460 int * blk_sz)
461 {
462 int blk_fd;
463 const char * fname;
464
465 blk_fd = (DDPT_ARG_IN == which_arg) ? op->idip->fd : op->odip->fd;
466 fname = (DDPT_ARG_IN == which_arg) ? op->idip->fn : op->odip->fn;
467 if (op->verbose > 2)
468 pr2serr("lin_get_blkdev_capacity: for %s\n", fname);
469 /* BLKGETSIZE64, BLKGETSIZE and BLKSSZGET macros problematic (from
470 * <linux/fs.h> or <sys/mount.h>). */
471 #ifdef BLKSSZGET
472 if ((ioctl(blk_fd, BLKSSZGET, blk_sz) < 0) && (*blk_sz > 0)) {
473 perror("BLKSSZGET ioctl error");
474 return -1;
475 } else {
476 #ifdef BLKGETSIZE64
477 uint64_t ull;
478
479 if (ioctl(blk_fd, BLKGETSIZE64, &ull) < 0) {
480
481 perror("BLKGETSIZE64 ioctl error");
482 return -1;
483 }
484 *num_blks = ((int64_t)ull / (int64_t)*blk_sz);
485 if (op->verbose > 5)
486 pr2serr("Used Linux BLKGETSIZE64 ioctl\n");
487 #else
488 unsigned long ul;
489
490 if (ioctl(blk_fd, BLKGETSIZE, &ul) < 0) {
491 perror("BLKGETSIZE ioctl error");
492 return -1;
493 }
494 *num_blks = (int64_t)ul;
495 if (op->verbose > 5)
496 pr2serr("Used Linux BLKGETSIZE ioctl\n");
497 #endif
498 }
499 return 0;
500 #else /* not BLKSSZGET */
501 blk_fd = blk_fd;
502 if (op->verbose)
503 pr2serr(" BLKSSZGET+BLKGETSIZE ioctl not available\n");
504 *num_blks = 0;
505 *blk_sz = 0;
506 return -1;
507 #endif
508 }
509 #endif /* BLKSSZGET */
510
511 #ifdef SG_LIB_FREEBSD
512 static int
fbsd_get_blkdev_capacity(struct opts_t * op,int which_arg,int64_t * num_blks,int * blk_sz)513 fbsd_get_blkdev_capacity(struct opts_t * op, int which_arg,
514 int64_t * num_blks, int * blk_sz)
515 {
516 // Why do kernels invent their own typedefs and not use C standards?
517 #define u_int unsigned int
518 off_t mediasize;
519 unsigned int sectorsize;
520 int blk_fd;
521 const char * fname;
522
523 blk_fd = (DDPT_ARG_IN == which_arg) ? op->idip->fd : op->odip->fd;
524 fname = (DDPT_ARG_IN == which_arg) ? op->idip->fn : op->odip->fn;
525 if (op->verbose > 2)
526 pr2serr("fbsd_get_blkdev_capacity: for %s\n", fname);
527
528 #ifdef __DragonFly__
529 struct partinfo partinfo;
530 if (ioctl(blk_fd, DIOCGPART, &partinfo) < 0) {
531 perror("DIOCGPART ioctl error, couldn't retrieve partinfo");
532 return -1;
533 }
534 *blk_sz = sectorsize = partinfo.media_blksize;
535 mediasize = partinfo.media_size;
536 #else
537 /* For FreeBSD post suggests that /usr/sbin/diskinfo uses
538 * ioctl(fd, DIOCGMEDIASIZE, &mediasize), where mediasize is an off_t.
539 * also: ioctl(fd, DIOCGSECTORSIZE, §orsize) */
540 if (ioctl(blk_fd, DIOCGSECTORSIZE, §orsize) < 0) {
541 perror("DIOCGSECTORSIZE ioctl error");
542 return -1;
543 }
544 *blk_sz = sectorsize;
545 if (ioctl(blk_fd, DIOCGMEDIASIZE, &mediasize) < 0) {
546 perror("DIOCGMEDIASIZE ioctl error");
547 return -1;
548 }
549 #endif
550 if (sectorsize)
551 *num_blks = mediasize / sectorsize;
552 else
553 *num_blks = 0;
554 return 0;
555 }
556 #endif
557
558 #ifdef SG_LIB_SOLARIS
559 static int
sol_get_blkdev_capacity(struct opts_t * op,int which_arg,int64_t * num_blks,int * blk_sz)560 sol_get_blkdev_capacity(struct opts_t * op, int which_arg,
561 int64_t * num_blks, int * blk_sz)
562 {
563 struct dk_minfo info;
564 int blk_fd;
565 const char * fname;
566
567 blk_fd = (DDPT_ARG_IN == which_arg) ? op->idip->fd : op->odip->fd;
568 fname = (DDPT_ARG_IN == which_arg) ? op->idip->fn : op->odip->fn;
569 if (op->verbose > 2)
570 pr2serr("sol_get_blkdev_capacity: for %s\n", fname);
571
572 /* this works on "char" block devs (e.g. in /dev/rdsk) but not /dev/dsk */
573 if (ioctl(blk_fd, DKIOCGMEDIAINFO , &info) < 0) {
574 perror("DKIOCGMEDIAINFO ioctl error");
575 *num_blks = 0;
576 *blk_sz = 0;
577 return -1;
578 }
579 *num_blks = info.dki_capacity;
580 *blk_sz = info.dki_lbsize;
581 return 0;
582 }
583 #endif
584
585 /* get_blkdev_capacity() returns 0 -> success or -1 -> failure.
586 * which_arg should either be DDPT_ARG_IN, DDPT_ARG_OUT or DDPT_ARG_OUT2.
587 * If successful writes back logical block size using the blk_sz pointer.
588 * Also writes back the number of logical blocks) on the block device using
589 * num_blks pointer. */
590 int
get_blkdev_capacity(struct opts_t * op,int which_arg,int64_t * num_blks,int * blk_sz)591 get_blkdev_capacity(struct opts_t * op, int which_arg, int64_t * num_blks,
592 int * blk_sz)
593 {
594 #ifdef SG_LIB_LINUX
595 return lin_get_blkdev_capacity(op, which_arg, num_blks, blk_sz);
596 #elif defined(SG_LIB_FREEBSD)
597 return fbsd_get_blkdev_capacity(op, which_arg, num_blks, blk_sz);
598 #elif defined(SG_LIB_SOLARIS)
599 return sol_get_blkdev_capacity(op, which_arg, num_blks, blk_sz);
600 #elif defined(SG_LIB_WIN32)
601 return win32_get_blkdev_capacity(op, which_arg, num_blks, blk_sz);
602 #else
603 return -1;
604 #endif
605 }
606
607 void
zero_coe_limit_count(struct opts_t * op)608 zero_coe_limit_count(struct opts_t * op)
609 {
610 if (op->coe_limit > 0)
611 op->coe_count = 0;
612 }
613
614 /* Print number of blocks, block size. If over 1 MB print size in MB
615 * (10**6 bytes), GB (10**9 bytes) or TB (10**12 bytes) to stderr. */
616 void
print_blk_sizes(const char * fname,const char * access_typ,int64_t num_blks,int blk_sz,int to_stderr)617 print_blk_sizes(const char * fname, const char * access_typ, int64_t num_blks,
618 int blk_sz, int to_stderr)
619 {
620 int mb, gb, tb;
621 size_t len;
622 int64_t n = 0;
623 char b[32];
624 char dec[4];
625 int (*print_p)(const char *, ...);
626
627 print_p = to_stderr ? pr2serr : printf;
628 if (num_blks <= 0) {
629 print_p(" %s [%s]: num_blocks=%" PRId64 ", block_size=%d\n", fname,
630 access_typ, num_blks, blk_sz);
631 return;
632 }
633 gb = 0;
634 if ((num_blks > 0) && (blk_sz > 0)) {
635 n = num_blks * blk_sz;
636 gb = n / 1000000000;
637 }
638 if (gb > 999999) {
639 tb = gb / 1000;
640 snprintf(b, sizeof(b), "%d", tb);
641 len = strlen(b); // len must be >= 4
642 dec[0] = b[len - 3];
643 dec[1] = b[len - 2];
644 dec[2] = '\0';
645 b[len - 3] = '\0';
646 print_p(" %s [%s]: num_blocks=%" PRId64 " [0x%" PRIx64 "], "
647 "block_size=%d, %s.%s PB\n", fname, access_typ, num_blks,
648 num_blks, blk_sz, b, dec);
649 } else if (gb > 99999) {
650 tb = gb / 1000;
651 print_p(" %s [%s]: num_blocks=%" PRId64 " [0x%" PRIx64 "], "
652 "block_size=%d, %d TB\n", fname, access_typ, num_blks,
653 num_blks, blk_sz, tb);
654 } else {
655 mb = n / 1000000;
656 if (mb > 999999) {
657 gb = mb / 1000;
658 snprintf(b, sizeof(b), "%d", gb);
659 len = strlen(b); // len must be >= 4
660 dec[0] = b[len - 3];
661 dec[1] = b[len - 2];
662 dec[2] = '\0';
663 b[len - 3] = '\0';
664 print_p(" %s [%s]: num_blocks=%" PRId64 " [0x%" PRIx64 "], "
665 "block_size=%d, %s.%s TB\n", fname, access_typ, num_blks,
666 num_blks, blk_sz, b, dec);
667 } else if (mb > 99999) {
668 gb = mb / 1000;
669 print_p(" %s [%s]: num_blocks=%" PRId64 " [0x%" PRIx64 "], "
670 "block_size=%d, %d GB\n", fname, access_typ, num_blks,
671 num_blks, blk_sz, gb);
672 } else if (mb > 999) {
673 snprintf(b, sizeof(b), "%d", mb);
674 len = strlen(b); // len must be >= 4
675 dec[0] = b[len - 3];
676 dec[1] = b[len - 2];
677 dec[2] = '\0';
678 b[len - 3] = '\0';
679 print_p(" %s [%s]: num_blocks=%" PRId64 " [0x%" PRIx64 "], "
680 "block_size=%d, %s.%s GB\n", fname, access_typ, num_blks,
681 num_blks, blk_sz, b, dec);
682 } else if (mb > 0) {
683 print_p(" %s [%s]: num_blocks=%" PRId64 " [0x%" PRIx64 "], "
684 "block_size=%d, %d MB%s\n", fname, access_typ, num_blks,
685 num_blks, blk_sz, mb, ((mb < 10) ? " approx" : ""));
686 } else
687 print_p(" %s [%s]: num_blocks=%" PRId64 " [0x%" PRIx64 "], "
688 "block_size=%d\n", fname, access_typ, num_blks, num_blks,
689 blk_sz);
690 }
691 }
692
693 void
calc_duration_init(struct opts_t * op)694 calc_duration_init(struct opts_t * op)
695 {
696 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
697 if (op->do_time) {
698 op->start_tm.tv_sec = 0;
699 op->start_tm.tv_nsec = 0;
700 if (0 == clock_gettime(CLOCK_MONOTONIC, &op->start_tm))
701 op->start_tm_valid = 1;
702 }
703 #elif defined(HAVE_GETTIMEOFDAY)
704 if (op->do_time) {
705 op->start_tm.tv_sec = 0;
706 op->start_tm.tv_usec = 0;
707 gettimeofday(&op->start_tm, NULL);
708 op->start_tm_valid = 1;
709 }
710 #else
711 if (op) { ; }
712 #endif
713 }
714
715 /* Calculates transfer throughput, typically in Megabytes per second.
716 * A megabyte in this context is 1000000 bytes (gives bigger numbers so
717 * is preferred by industry). The clock_gettime() interface is preferred
718 * since time is guaranteed to advance; gettimeofday() is impacted if the
719 * user (or something like ntpd) changes the time.
720 * Also if the transfer is large enough and isn't about to finish, it
721 * makes an estimate of the time remaining. */
722 void
calc_duration_throughput(const char * leadin,int contin,struct opts_t * op)723 calc_duration_throughput(const char * leadin, int contin, struct opts_t * op)
724 {
725 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
726 struct timespec end_tm, res_tm;
727 double a, b, r;
728 int secs, h, m, use_out_full;
729
730 if (op->start_tm_valid && (op->start_tm.tv_sec || op->start_tm.tv_nsec)) {
731 use_out_full = ((0 == op->in_full) && (op->obs > 0));
732 clock_gettime(CLOCK_MONOTONIC, &end_tm);
733 res_tm.tv_sec = end_tm.tv_sec - op->start_tm.tv_sec;
734 res_tm.tv_nsec = end_tm.tv_nsec - op->start_tm.tv_nsec;
735 if (res_tm.tv_nsec < 0) {
736 --res_tm.tv_sec;
737 res_tm.tv_nsec += 1000000000;
738 }
739 a = res_tm.tv_sec;
740 a += (0.000001 * (res_tm.tv_nsec / 1000));
741 if (use_out_full)
742 b = (double)op->obs * op->out_full;
743 else
744 b = (double)op->ibs_hold * op->in_full;
745 pr2serr("%stime to %s data%s: %d.%06d secs", leadin,
746 (op->read1_or_transfer ? "read" : "transfer"),
747 (contin ? " so far" : ""), (int)res_tm.tv_sec,
748 (int)(res_tm.tv_nsec / 1000));
749 r = 0.0;
750 if ((a > 0.00001) && (b > 511)) {
751 r = b / (a * 1000000.0);
752 if (r < 1.0)
753 pr2serr(" at %.1f KB/sec\n", r * 1000);
754 else
755 pr2serr(" at %.2f MB/sec\n", r);
756 } else
757 pr2serr("\n");
758 if (contin && (! op->reading_fifo) && (r > 0.01) &&
759 (op->dd_count > 100)) {
760 secs = (int)(((double)op->ibs_hold * op->dd_count) /
761 (r * 1000000));
762 if (secs > 10) {
763 h = secs / 3600;
764 secs = secs - (h * 3600);
765 m = secs / 60;
766 secs = secs - (m * 60);
767 if (h > 0)
768 pr2serr("%sestimated time remaining: %d:%02d:%02d\n",
769 leadin, h, m, secs);
770 else
771 pr2serr("%sestimated time remaining: %d:%02d\n",
772 leadin, m, secs);
773 }
774 }
775 }
776 #elif defined(HAVE_GETTIMEOFDAY)
777 struct timeval end_tm, res_tm;
778 double a, b, r;
779 int secs, h, m;
780 int64_t blks;
781
782 if (op->start_tm_valid && (op->start_tm.tv_sec || op->start_tm.tv_usec)) {
783 blks = op->in_full;
784 gettimeofday(&end_tm, NULL);
785 res_tm.tv_sec = end_tm.tv_sec - op->start_tm.tv_sec;
786 res_tm.tv_usec = end_tm.tv_usec - op->start_tm.tv_usec;
787 if (res_tm.tv_usec < 0) {
788 --res_tm.tv_sec;
789 res_tm.tv_usec += 1000000;
790 }
791 a = res_tm.tv_sec;
792 a += (0.000001 * res_tm.tv_usec);
793 b = (double)op->ibs_hold * blks;
794 pr2serr("%stime to %s data%s: %d.%06d secs", leadin,
795 (op->read1_or_transfer ? "read" : "transfer"),
796 (contin ? " so far" : ""), (int)res_tm.tv_sec,
797 (int)res_tm.tv_usec);
798 r = 0.0;
799 if ((a > 0.00001) && (b > 511)) {
800 r = b / (a * 1000000.0);
801 if (r < 1.0)
802 pr2serr(" at %.1f KB/sec\n", r * 1000);
803 else
804 pr2serr(" at %.2f MB/sec\n", r);
805 } else
806 pr2serr("\n");
807 if (contin && (! op->reading_fifo) && (r > 0.01) &&
808 (op->dd_count > 100)) {
809 secs = (int)(((double)op->ibs_hold * op->dd_count) /
810 (r * 1000000));
811 if (secs > 10) {
812 h = secs / 3600;
813 secs = secs - (h * 3600);
814 m = secs / 60;
815 secs = secs - (m * 60);
816 if (h > 0)
817 pr2serr("%sestimated time remaining: "
818 "%d:%02d:%02d\n", leadin, h, m, secs);
819 else
820 pr2serr("%sestimated time remaining: "
821 "%d:%02d\n", leadin, m, secs);
822 }
823 }
824 }
825 #else /* no clock reading functions available */
826 if (leadin) { ; } // suppress warning
827 if (contin) { ; } // suppress warning
828 #endif
829 }
830
831 /* Create errblk file (see iflag=errblk) and if we have gettimeofday
832 * puts are start timestampl on the first line. */
833 void
errblk_open(struct opts_t * op)834 errblk_open(struct opts_t * op)
835 {
836 op->errblk_fp = fopen(errblk_file, "a"); /* append */
837 if (NULL == op->errblk_fp)
838 pr2serr("unable to open or create %s\n", errblk_file);
839 else {
840 #ifdef HAVE_GETTIMEOFDAY
841 {
842 time_t t;
843 char b[64];
844
845 t = time(NULL);
846 strftime(b, sizeof(b), "# start: %Y-%m-%d %H:%M:%S\n",
847 localtime(&t));
848 fputs(b, op->errblk_fp);
849 }
850 #else
851 fputs("# start\n", op->errblk_fp);
852 #endif
853 }
854 }
855
856 void /* Global function, used by ddpt_pt.c */
errblk_put(uint64_t lba,struct opts_t * op)857 errblk_put(uint64_t lba, struct opts_t * op)
858 {
859 if (op->errblk_fp)
860 fprintf(op->errblk_fp, "0x%" PRIx64 "\n", lba);
861 }
862
863 void /* Global function, used by ddpt_pt.c */
errblk_put_range(uint64_t lba,int num,struct opts_t * op)864 errblk_put_range(uint64_t lba, int num, struct opts_t * op)
865 {
866 if (op->errblk_fp) {
867 if (1 == num)
868 errblk_put(lba, op);
869 else if (num > 1)
870 fprintf(op->errblk_fp, "0x%" PRIx64 "-0x%" PRIx64 "\n", lba,
871 lba + (num - 1));
872 }
873 }
874
875 void
errblk_close(struct opts_t * op)876 errblk_close(struct opts_t * op)
877 {
878 if (op->errblk_fp) {
879 #ifdef HAVE_GETTIMEOFDAY
880 {
881 time_t t;
882 char b[64];
883
884 t = time(NULL);
885 strftime(b, sizeof(b), "# stop: %Y-%m-%d %H:%M:%S\n",
886 localtime(&t));
887 fputs(b, op->errblk_fp);
888 }
889 #else
890 fputs("# stop\n", op->errblk_fp);
891 #endif
892 fclose(op->errblk_fp);
893 op->errblk_fp = NULL;
894 }
895 }
896
897
898 #ifdef SG_LIB_LINUX
899
900 /* Summarise previous consecutive same-length reads. Do that when:
901 * - read length (res) differs from the previous read length, and
902 * - there were more than one consecutive reads of the same length
903 * The str argument is a prefix string, typically one or two spaces, used
904 * to e.g. make output line up when printing on kill -USR1. */
905 void
print_tape_summary(struct opts_t * op,int res,const char * str)906 print_tape_summary(struct opts_t * op, int res, const char * str)
907 {
908 int len = op->last_tape_read_len;
909 int num = op->read_tape_numbytes;
910
911 if ((op->verbose > 1) && (res != len) && (op->consec_same_len_reads >= 1))
912 pr2serr("%s(%d%s read%s of %d byte%s)\n", str,
913 op->consec_same_len_reads, (len < num) ? " short" : "",
914 (op->consec_same_len_reads != 1) ? "s" : "", len,
915 (len != 1) ? "s" : "");
916 }
917
918 static void
show_tape_pos_error(const char * postfix)919 show_tape_pos_error(const char * postfix)
920 {
921 pr2serr("Could not get tape position%s: %s\n", postfix,
922 safe_strerror(errno));
923 }
924
925 /* Print tape position(s) if verbose > 1. If both reading from and writing to
926 * tape, make clear in output which is which. Also only print the position if
927 * necessary, i.e. not already printed.
928 * Prefix argument is e.g. "Initial " or "Final ". */
929 void
print_tape_pos(const char * prefix,const char * postfix,struct opts_t * op)930 print_tape_pos(const char * prefix, const char * postfix, struct opts_t * op)
931 {
932 static int lastreadpos, lastwritepos;
933 static char lastreadposvalid = 0;
934 static char lastwriteposvalid = 0;
935 int res;
936 struct mtpos pos;
937
938 if (op->verbose > 1) {
939 if (FT_TAPE & op->idip->d_type) {
940 res = ioctl(op->idip->fd, MTIOCPOS, &pos);
941 if (0 == res) {
942 if ((pos.mt_blkno != lastreadpos) ||
943 (0 == lastreadposvalid)) {
944 lastreadpos = pos.mt_blkno;
945 lastreadposvalid = 1;
946 pr2serr("%stape position%s: %u%s\n", prefix,
947 (FT_TAPE & op->odip->d_type) ? " (reading)" : "",
948 lastreadpos, postfix);
949 }
950 } else {
951 lastreadposvalid = 0;
952 show_tape_pos_error((FT_TAPE & op->odip->d_type) ?
953 " (reading)" : "");
954 }
955 }
956
957 if (FT_TAPE & op->odip->d_type) {
958 res = ioctl(op->odip->fd, MTIOCPOS, &pos);
959 if (0 == res) {
960 if ((pos.mt_blkno != lastwritepos) ||
961 (0 == lastwriteposvalid)) {
962 lastwritepos = pos.mt_blkno;
963 lastwriteposvalid = 1;
964 pr2serr("%stape position%s: %u%s\n", prefix,
965 (FT_TAPE & op->idip->d_type) ? " (writing)" : "",
966 lastwritepos, postfix);
967 }
968 } else {
969 lastwriteposvalid = 0;
970 show_tape_pos_error((FT_TAPE & op->idip->d_type) ?
971 " (writing)" : "");
972 }
973 }
974
975 }
976 }
977
978 #endif /* SG_LIB_LINUX */
979
980
981 /* The use of signals is borrowed from GNU's dd source code which is
982 * found in their coreutils package. If SA_NOCLDSTOP is non-zero then
983 * a modern Posix compliant version of signals is assumed. Still
984 * thinking about SIGHUP which will be delivered if the controlling
985 * process/terminal is terminated or receives SIGHUP. */
986
987 /* If nonzero, the value of the pending fatal signal. */
988 static sig_atomic_t volatile interrupt_signal;
989
990 /* A count of pending info(usr1) signals, decremented as processed */
991 static sig_atomic_t volatile info_signals_pending;
992
993 static struct val_str_t signum_name_arr[] = {
994 {SIGINT, "SIGINT"},
995 {SIGQUIT, "SIGQUIT"},
996 {SIGPIPE, "SIGPIPE"},
997 #if SIGINFO == SIGUSR1
998 {SIGUSR1, "SIGUSR1"},
999 #else
1000 {SIGINFO, "SIGINFO"},
1001 #endif
1002 #ifndef SG_LIB_WIN32
1003 {SIGHUP, "SIGHUP"},
1004 #endif
1005 {0, NULL},
1006 };
1007
1008
1009
1010 /* Return signal name for signum if known, else return signum as a string. */
1011 static const char *
get_signal_name(int signum,char * b,int blen)1012 get_signal_name(int signum, char * b, int blen)
1013 {
1014 const struct val_str_t * sp;
1015
1016 for (sp = signum_name_arr; sp->num; ++sp) {
1017 if (signum == sp->num)
1018 break;
1019 }
1020 if (blen < 1)
1021 return b;
1022 b[blen - 1] = '\0';
1023 if (sp->num)
1024 strncpy(b, sp->name, blen - 1);
1025 else
1026 snprintf(b, blen, "%d", signum);
1027 return b;
1028 }
1029
1030 /* An ordinary signal was received; arrange for the program to exit. */
1031 static void
interrupt_handler(int sig)1032 interrupt_handler(int sig)
1033 {
1034 if (! SA_RESETHAND)
1035 signal(sig, SIG_DFL);
1036 interrupt_signal = sig;
1037 }
1038
1039 /* An info signal was received; arrange for the program to print status. */
1040 static void
siginfo_handler(int sig)1041 siginfo_handler(int sig)
1042 {
1043 if (! SA_NOCLDSTOP)
1044 signal(sig, siginfo_handler);
1045 ++info_signals_pending;
1046 }
1047
1048 /* Install the signal handlers. We try to cope gracefully with signals whose
1049 * disposition is 'ignored'. SUSv3 recommends that a process should start
1050 * with no blocked signals; if needed unblock SIGINFO, SIGINT or SIGPIPE. */
1051 void
install_signal_handlers(struct opts_t * op)1052 install_signal_handlers(struct opts_t * op)
1053 {
1054 #if SIGINFO == SIGUSR1
1055 const char * sname = "SIGUSR1";
1056 #else
1057 const char * sname = "SIGINFO";
1058 #endif
1059
1060 if (op->verbose > 2)
1061 pr2serr(" >> %s signal implementation assumed "
1062 "[SA_NOCLDSTOP=%d], %smasking during IO\n",
1063 (SA_NOCLDSTOP ? "modern" : "old"), SA_NOCLDSTOP,
1064 (op->interrupt_io ? "not " : ""));
1065 #if SA_NOCLDSTOP
1066 struct sigaction act;
1067 sigset_t starting_mask;
1068 int num_members = 0;
1069 int unblock_starting_mask = 0;
1070 sigemptyset(&op->caught_signals);
1071 sigemptyset(&op->orig_mask);
1072 sigaction(SIGINFO, NULL, &act);
1073 if (act.sa_handler != SIG_IGN)
1074 sigaddset(&op->caught_signals, SIGINFO);
1075 else if (op->verbose)
1076 pr2serr("%s ignored, progress reports not available\n", sname);
1077 sigaction(SIGINT, NULL, &act);
1078 if (act.sa_handler != SIG_IGN)
1079 sigaddset(&op->caught_signals, SIGINT);
1080 else if (op->verbose)
1081 pr2serr("SIGINT ignored\n");
1082 sigaction(SIGPIPE, NULL, &act);
1083 if (act.sa_handler != SIG_IGN)
1084 sigaddset(&op->caught_signals, SIGPIPE);
1085 else if (op->verbose)
1086 pr2serr("SIGPIPE ignored\n");
1087
1088 sigprocmask(SIG_UNBLOCK /* ignored */, NULL, &starting_mask);
1089 if (sigismember(&starting_mask, SIGINFO)) {
1090 if (op->verbose)
1091 pr2serr("%s blocked on entry, unblock\n", sname);
1092 ++unblock_starting_mask;
1093 }
1094 if (sigismember(&starting_mask, SIGINT)) {
1095 if (op->verbose)
1096 pr2serr("SIGINT blocked on entry, unblock\n");
1097 ++unblock_starting_mask;
1098 }
1099 if (sigismember(&starting_mask, SIGPIPE)) {
1100 if (op->verbose)
1101 pr2serr("SIGPIPE blocked on entry, unblock\n");
1102 ++unblock_starting_mask;
1103 }
1104 act.sa_mask = op->caught_signals;
1105
1106 if (sigismember(&op->caught_signals, SIGINFO)) {
1107 act.sa_handler = siginfo_handler;
1108 act.sa_flags = 0;
1109 sigaction(SIGINFO, &act, NULL);
1110 ++num_members;
1111 }
1112
1113 if (sigismember(&op->caught_signals, SIGINT)) {
1114 act.sa_handler = interrupt_handler;
1115 act.sa_flags = SA_NODEFER | SA_RESETHAND;
1116 sigaction(SIGINT, &act, NULL);
1117 ++num_members;
1118 }
1119
1120 if (sigismember(&op->caught_signals, SIGPIPE)) {
1121 act.sa_handler = interrupt_handler;
1122 act.sa_flags = SA_NODEFER | SA_RESETHAND;
1123 sigaction(SIGPIPE, &act, NULL);
1124 ++num_members;
1125 }
1126 if (unblock_starting_mask)
1127 sigprocmask(SIG_UNBLOCK, &op->caught_signals, NULL);
1128
1129 if ((0 == op->interrupt_io) && (num_members > 0))
1130 sigprocmask(SIG_BLOCK, &op->caught_signals, &op->orig_mask);
1131 #else /* not SA_NOCLDSTOP */
1132 if (op) { ; } /* suppress warning */
1133 if (signal(SIGINFO, SIG_IGN) != SIG_IGN) {
1134 signal(SIGINFO, siginfo_handler);
1135 siginterrupt(SIGINFO, 1);
1136 } else if (op->verbose)
1137 pr2serr("old %s ignored, progress report not available\n", sname);
1138 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
1139 signal(SIGINT, interrupt_handler);
1140 siginterrupt(SIGINT, 1);
1141 } else if (op->verbose)
1142 pr2serr("old SIGINT ignored\n");
1143 #endif /* SA_NOCLDSTOP */
1144 }
1145
1146 /* Process any pending signals and perhaps do delay. If signals are caught,
1147 * this function should be called periodically. Ideally there should never
1148 * be an unbounded amount of time when signals are not being processed. */
1149 void /* Global function, used by ddpt_xcopy.c */
signals_process_delay(struct opts_t * op,int delay_type)1150 signals_process_delay(struct opts_t * op, int delay_type)
1151 {
1152 char b[32];
1153 int got_something = 0;
1154 int delay = 0;
1155
1156 #if SA_NOCLDSTOP
1157 int found_pending = 0;
1158
1159 if ((0 == op->interrupt_io) &&
1160 (sigismember(&op->caught_signals, SIGINT) ||
1161 sigismember(&op->caught_signals, SIGPIPE) ||
1162 sigismember(&op->caught_signals, SIGINFO))) {
1163 sigset_t pending_set;
1164
1165 sigpending(&pending_set);
1166 if (sigismember(&pending_set, SIGINT) ||
1167 sigismember(&pending_set, SIGPIPE) ||
1168 sigismember(&pending_set, SIGINFO)) {
1169 /* Signal handler for a pending signal run during suspend */
1170 sigsuspend(&op->orig_mask);
1171 found_pending = 1;
1172 } else { /* nothing pending so perhaps delay */
1173 if ((op->delay > 0) && (DELAY_COPY_SEGMENT == delay_type))
1174 delay = op->delay;
1175 else if ((op->wdelay > 0) && (DELAY_WRITE == delay_type)) {
1176 if (op->subsequent_wdelay)
1177 delay = op->wdelay;
1178 else
1179 op->subsequent_wdelay = 1;
1180 }
1181 if (delay) {
1182 sigprocmask(SIG_SETMASK, &op->orig_mask, NULL);
1183 if (op->verbose > 3)
1184 pr2serr("delay=%d milliseconds [%s]\n", delay,
1185 ((DELAY_WRITE == delay_type) ? "write" : "copy"));
1186 sleep_ms(delay);
1187 sigprocmask(SIG_BLOCK, &op->caught_signals, NULL);
1188 }
1189 if (! (interrupt_signal || info_signals_pending))
1190 return;
1191 }
1192 }
1193 #endif
1194
1195 while (interrupt_signal || info_signals_pending) {
1196 int interrupt;
1197 int infos;
1198
1199 got_something = 1;
1200 #if SA_NOCLDSTOP
1201 if (! found_pending)
1202 sigprocmask(SIG_BLOCK, &op->caught_signals, NULL);
1203 #endif
1204
1205 /* Reload interrupt_signal and info_signals_pending, in case a new
1206 signal was handled before sigprocmask took effect. */
1207 interrupt = interrupt_signal;
1208 infos = info_signals_pending;
1209
1210 if (infos)
1211 info_signals_pending = infos - 1;
1212
1213 #if SA_NOCLDSTOP
1214 if (! found_pending)
1215 sigprocmask(SIG_SETMASK, &op->orig_mask, NULL);
1216 #endif
1217
1218 if (interrupt) {
1219 pr2serr("Interrupted by signal %s\n",
1220 get_signal_name(interrupt, b, sizeof(b)));
1221 print_stats("", op, 0);
1222 /* Don't show next message if using oflag=pre-alloc and we didn't
1223 * use FALLOC_FL_KEEP_SIZE */
1224 if ((0 == op->reading_fifo) && (FT_REG & op->odip->d_type_hold)
1225 && (0 == op->oflagp->prealloc)) {
1226 if (op->oflagp->strunc) {
1227 int64_t osize = (op->seek * op->obs);
1228
1229 pr2serr(">> Did not perform: "
1230 "'truncate --size=%" PRId64 " %s'\n",
1231 osize, op->odip->fn);
1232 pr2serr(">> User should check and perform by hand if "
1233 "necessary\n");
1234 }
1235 pr2serr("To resume, invoke with same arguments plus "
1236 "oflag=resume\n");
1237 }
1238 // Could more cleanup or suggestions be made here?
1239 } else {
1240 pr2serr("Progress report:\n");
1241 print_stats(" ", op, 0);
1242 if (op->do_time)
1243 calc_duration_throughput(" ", 1, op);
1244 pr2serr(" continuing ...\n");
1245 }
1246 if (interrupt) {
1247 #if SA_NOCLDSTOP
1248 if (found_pending) {
1249 sigset_t int_set;
1250
1251 sigemptyset(&int_set);
1252 sigaddset(&int_set, interrupt);
1253 sigprocmask(SIG_UNBLOCK, &int_set, NULL);
1254 }
1255 #endif
1256 raise(interrupt);
1257 }
1258 }
1259
1260 if (! got_something) {
1261 delay = 0;
1262 if ((op->delay > 0) && (DELAY_COPY_SEGMENT == delay_type))
1263 delay = op->delay;
1264 else if ((op->wdelay > 0) && (DELAY_WRITE == delay_type)) {
1265 if (op->subsequent_wdelay)
1266 delay = op->wdelay;
1267 else
1268 op->subsequent_wdelay = 1;
1269 }
1270 if (delay)
1271 sleep_ms(op->delay);
1272 }
1273 }
1274
1275 static const char * assoc_arr[] =
1276 {
1277 "addressed logical unit",
1278 "target port", /* that received request; unless SCSI ports VPD */
1279 "target device that contains addressed lu",
1280 "reserved [0x3]",
1281 };
1282
1283 static const char * code_set_arr[] =
1284 {
1285 "Reserved [0x0]",
1286 "Binary",
1287 "ASCII",
1288 "UTF-8",
1289 "[0x4]", "[0x5]", "[0x6]", "[0x7]", "[0x8]", "[0x9]", "[0xa]", "[0xb]",
1290 "[0xc]", "[0xd]", "[0xe]", "[0xf]",
1291 };
1292
1293 static const char * desig_type_arr[] =
1294 {
1295 "vendor specific [0x0]", /* SCSI_IDENT_DEVICE_VENDOR */
1296 "T10 vendor identification", /* SCSI_IDENT_DEVICE_T10 */
1297 "EUI-64 based", /* SCSI_IDENT_DEVICE_EUI64 */
1298 "NAA", /* SCSI_IDENT_DEVICE_NAA */
1299 "Relative target port", /* SCSI_IDENT_PORT_RELATIVE */
1300 "Target port group", /* SCSI_IDENT_PORT_TP_GROUP */
1301 "Logical unit group", /* SCSI_IDENT_PORT_LU_GROUP */
1302 "MD5 logical unit identifier", /* SCSI_IDENT_DEVICE_MD5 */
1303 "SCSI name string", /* SCSI_IDENT_DEVICE_SCSINAME */
1304 "Protocol specific port identifier", /* spc4r36 */
1305 "[0xa]", "[0xb]", "[0xc]", "[0xd]", "[0xe]", "[0xf]",
1306 };
1307
1308 void
decode_designation_descriptor(const unsigned char * ucp,int len_less_4,int to_stderr,int verb)1309 decode_designation_descriptor(const unsigned char * ucp, int len_less_4,
1310 int to_stderr, int verb)
1311 {
1312 int m, p_id, piv, c_set, assoc, desig_type, d_id, naa, i_len;
1313 int k;
1314 const unsigned char * ip;
1315 uint64_t vsei;
1316 char b[80];
1317 int (*print_p)(const char *, ...);
1318 void (*dStrHexp)(const char *, int, int);
1319
1320 print_p = to_stderr ? pr2serr : printf;
1321 dStrHexp = to_stderr ? dStrHexErr : dStrHex;
1322 ip = ucp + 4;
1323 i_len = len_less_4; /* valid ucp length is (len_less_4 + 4) */
1324 p_id = ((ucp[0] >> 4) & 0xf);
1325 c_set = (ucp[0] & 0xf);
1326 piv = ((ucp[1] & 0x80) ? 1 : 0);
1327 assoc = ((ucp[1] >> 4) & 0x3);
1328 desig_type = (ucp[1] & 0xf);
1329 print_p(" designator_type: %s, code_set: %s\n",
1330 desig_type_arr[desig_type], code_set_arr[c_set]);
1331 print_p(" associated with the %s\n", assoc_arr[assoc]);
1332 if (piv && ((1 == assoc) || (2 == assoc)))
1333 print_p(" transport: %s\n",
1334 sg_get_trans_proto_str(p_id, sizeof(b), b));
1335
1336 switch (desig_type) {
1337 case 0: /* vendor specific */
1338 k = 0;
1339 if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */
1340 for (k = 0; (k < i_len) && isprint(ip[k]); ++k)
1341 ;
1342 if (k >= i_len)
1343 k = 1;
1344 }
1345 if (k)
1346 print_p(" vendor specific: %.*s\n", i_len, ip);
1347 else {
1348 print_p(" vendor specific:\n");
1349 dStrHexp((const char *)ip, i_len, -1);
1350 }
1351 break;
1352 case 1: /* T10 vendor identification */
1353 print_p(" vendor id: %.8s\n", ip);
1354 if (i_len > 8)
1355 print_p(" vendor specific: %.*s\n", i_len - 8, ip + 8);
1356 break;
1357 case 2: /* EUI-64 based */
1358 if ((8 != i_len) && (12 != i_len) && (16 != i_len)) {
1359 print_p(" << expect 8, 12 and 16 byte EUI, got %d>>\n",
1360 i_len);
1361 dStrHexp((const char *)ip, i_len, 0);
1362 break;
1363 }
1364 print_p(" 0x");
1365 for (m = 0; m < i_len; ++m)
1366 print_p("%02x", (unsigned int)ip[m]);
1367 print_p("\n");
1368 break;
1369 case 3: /* NAA */
1370 naa = (ip[0] >> 4) & 0xff;
1371 if (1 != c_set) {
1372 print_p(" << expected binary code set (1), got %d for "
1373 "NAA=%d>>\n", c_set, naa);
1374 dStrHexp((const char *)ip, i_len, -1);
1375 break;
1376 }
1377 if ((5 == naa) && (0x10 == i_len)) {
1378 if (verb > 2)
1379 print_p(" << unexpected NAA 5 len 16, assuming NAA 6 "
1380 ">>\n");
1381 naa = 6;
1382 }
1383 switch (naa) {
1384 case 2: /* NAA: IEEE extended */
1385 if (8 != i_len) {
1386 print_p(" << unexpected NAA 2 identifier length: "
1387 "0x%x>>\n", i_len);
1388 dStrHexp((const char *)ip, i_len, -1);
1389 break;
1390 }
1391 d_id = (((ip[0] & 0xf) << 8) | ip[1]);
1392 /* c_id = ((ip[2] << 16) | (ip[3] << 8) | ip[4]); */
1393 /* vsi = ((ip[5] << 16) | (ip[6] << 8) | ip[7]); */
1394 print_p(" 0x");
1395 for (m = 0; m < 8; ++m)
1396 print_p("%02x", (unsigned int)ip[m]);
1397 print_p("\n");
1398 break;
1399 case 3: /* NAA: Locally assigned */
1400 case 5: /* NAA: IEEE Registered */
1401 if (8 != i_len) {
1402 print_p(" << unexpected NAA 3 or 5 identifier length: "
1403 "0x%x>>\n", i_len);
1404 dStrHexp((const char *)ip, i_len, -1);
1405 break;
1406 }
1407 /* c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | */
1408 /* (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); */
1409 vsei = ip[3] & 0xf;
1410 for (m = 1; m < 5; ++m) {
1411 vsei <<= 8;
1412 vsei |= ip[3 + m];
1413 }
1414 print_p(" 0x");
1415 for (m = 0; m < 8; ++m)
1416 print_p("%02x", (unsigned int)ip[m]);
1417 print_p("\n");
1418 break;
1419 case 6: /* NAA IEEE registered extended */
1420 if (16 != i_len) {
1421 print_p(" << unexpected NAA 6 identifier length: "
1422 "0x%x>>\n", i_len);
1423 dStrHexp((const char *)ip, i_len, -1);
1424 break;
1425 }
1426 /* c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | */
1427 /* (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); */
1428 vsei = ip[3] & 0xf;
1429 for (m = 1; m < 5; ++m) {
1430 vsei <<= 8;
1431 vsei |= ip[3 + m];
1432 }
1433 print_p(" 0x");
1434 for (m = 0; m < 16; ++m)
1435 print_p("%02x", (unsigned int)ip[m]);
1436 print_p("\n");
1437 break;
1438 default:
1439 print_p(" << expected NAA nibble of 2, 3, 5 or 6, got "
1440 "%d>>\n", naa);
1441 dStrHexp((const char *)ip, i_len, -1);
1442 break;
1443 }
1444 break;
1445 case 4: /* Relative target port */
1446 if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1447 print_p(" << expected binary code_set, target port "
1448 "association, length 4>>\n");
1449 dStrHexp((const char *)ip, i_len, 0);
1450 break;
1451 }
1452 d_id = ((ip[2] << 8) | ip[3]);
1453 print_p(" Relative target port: 0x%x\n", d_id);
1454 break;
1455 case 5: /* (primary) Target port group */
1456 if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1457 print_p(" << expected binary code_set, target port "
1458 "association, length 4>>\n");
1459 dStrHexp((const char *)ip, i_len, 0);
1460 break;
1461 }
1462 d_id = ((ip[2] << 8) | ip[3]);
1463 print_p(" Target port group: 0x%x\n", d_id);
1464 break;
1465 case 6: /* Logical unit group */
1466 if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
1467 print_p(" << expected binary code_set, logical unit "
1468 "association, length 4>>\n");
1469 dStrHexp((const char *)ip, i_len, 0);
1470 break;
1471 }
1472 d_id = ((ip[2] << 8) | ip[3]);
1473 print_p(" Logical unit group: 0x%x\n", d_id);
1474 break;
1475 case 7: /* MD5 logical unit identifier */
1476 if ((1 != c_set) || (0 != assoc)) {
1477 print_p(" << expected binary code_set, logical unit "
1478 "association>>\n");
1479 dStrHexp((const char *)ip, i_len, 0);
1480 break;
1481 }
1482 print_p(" MD5 logical unit identifier:\n");
1483 dStrHexp((const char *)ip, i_len, 0);
1484 break;
1485 case 8: /* SCSI name string */
1486 if (3 != c_set) {
1487 print_p(" << expected UTF-8 code_set>>\n");
1488 dStrHexp((const char *)ip, i_len, 0);
1489 break;
1490 }
1491 print_p(" SCSI name string:\n");
1492 /* does %s print out UTF-8 ok??
1493 * Seems to depend on the locale. Looks ok here with my
1494 * locale setting: en_AU.UTF-8
1495 */
1496 print_p(" %s\n", (const char *)ip);
1497 break;
1498 case 9: /* Protocol specific port identifier */
1499 /* added in spc4r36, PIV must be set, proto_id indicates */
1500 /* whether UAS (USB) or SOP (PCIe) or ... */
1501 if (! piv)
1502 print_p(" >>>> Protocol specific port identifier "
1503 "expects protocol\n"
1504 " identifier to be valid and it is not\n");
1505 if (TPROTO_UAS == p_id) {
1506 print_p(" USB device address: 0x%x\n", 0x7f & ip[0]);
1507 print_p(" USB interface number: 0x%x\n", ip[2]);
1508 } else if (TPROTO_SOP == p_id) {
1509 print_p(" PCIe routing ID, bus number: 0x%x\n", ip[0]);
1510 print_p(" function number: 0x%x\n", ip[1]);
1511 print_p(" [or device number: 0x%x, function number: "
1512 "0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
1513 } else
1514 print_p(" >>>> unexpected protocol indentifier: 0x%x\n"
1515 " with Protocol specific port "
1516 "identifier\n", p_id);
1517 break;
1518 default: /* reserved */
1519 print_p(" reserved designator=0x%x\n", desig_type);
1520 dStrHexp((const char *)ip, i_len, 0);
1521 break;
1522 }
1523 }
1524
1525 /* Helper for case when EIO or EREMOTE errno suggests the equivalent
1526 * of a medium error. Returns 0 unless coe_limit exceeded. */
1527 int /* Global function, used by ddpt_win32.c */
coe_process_eio(struct opts_t * op,int64_t skip)1528 coe_process_eio(struct opts_t * op, int64_t skip)
1529 {
1530 if ((op->coe_limit > 0) && (++op->coe_count > op->coe_limit)) {
1531 pr2serr(">> coe_limit on consecutive reads "
1532 "exceeded\n");
1533 return SG_LIB_CAT_MEDIUM_HARD;
1534 }
1535 if (op->highest_unrecovered < 0) {
1536 op->highest_unrecovered = skip;
1537 op->lowest_unrecovered = skip;
1538 } else {
1539 if (skip < op->lowest_unrecovered)
1540 op->lowest_unrecovered = skip;
1541 if (skip > op->highest_unrecovered)
1542 op->highest_unrecovered = skip;
1543 }
1544 ++op->unrecovered_errs;
1545 ++op->in_partial;
1546 --op->in_full;
1547 pr2serr(">> unrecovered read error at blk=%" PRId64 ", "
1548 "substitute zeros\n", skip);
1549 return 0;
1550 }
1551
1552 char *
rod_type_str(uint32_t rt,char * b,int b_mlen)1553 rod_type_str(uint32_t rt, char * b, int b_mlen)
1554 {
1555 int got_pit = 0;
1556 const char * cp = NULL;
1557 const char * pitp = "point in time copy - ";
1558
1559 switch (rt) {
1560 case RODT_CM_INTERNAL:
1561 cp = "copy manager internal";
1562 break;
1563 case RODT_ACCESS_ON_REF:
1564 cp = "access upon reference";
1565 break;
1566 case RODT_PIT_DEF:
1567 cp = "default";
1568 got_pit = 1;
1569 break;
1570 case RODT_PIT_VULN:
1571 cp = "change vulnerable";
1572 got_pit = 1;
1573 break;
1574 case RODT_PIT_PERS:
1575 cp = "persistent";
1576 got_pit = 1;
1577 break;
1578 case RODT_PIT_ANY:
1579 cp = "any";
1580 got_pit = 1;
1581 break;
1582 case RODT_BLK_ZERO:
1583 cp = "block device zero";
1584 break;
1585 default:
1586 if (rt >= 0xfffffff0)
1587 cp = "vendor specific";
1588 else if (rt >= 0xff000000)
1589 cp = "device type specific";
1590 else
1591 cp = "reserved";
1592 break;
1593 }
1594 if (cp)
1595 snprintf(b, b_mlen, "%s%s [0x%" PRIx32 "]", (got_pit ? pitp : ""),
1596 cp, rt);
1597 else
1598 snprintf(b, b_mlen, "0x%" PRIx32 "", rt);
1599 return b;
1600 }
1601
1602 char *
rt_cm_id_str(const unsigned char * rtp,int rt_len,char * b,int b_mlen)1603 rt_cm_id_str(const unsigned char * rtp, int rt_len, char * b, int b_mlen)
1604 {
1605 int m, num;
1606
1607 if (rt_len < 16)
1608 snprintf(b, b_mlen, "ROD Token too short (%d < 16)\n", rt_len);
1609 num = 0;
1610 num += snprintf(b, b_mlen, "0x");
1611 for (m = 0; ((m < 8) && (num < b_mlen)); ++m)
1612 num += snprintf(b + num, b_mlen - num, "%02x",
1613 (unsigned int)rtp[8 + m]);
1614 return b;
1615 }
1616
1617 void
print_exit_status_msg(const char * prefix,int exit_stat,int to_stderr)1618 print_exit_status_msg(const char * prefix, int exit_stat, int to_stderr)
1619 {
1620 int (*print_p)(const char *, ...);
1621 char b[80];
1622
1623 print_p = to_stderr ? pr2serr : printf;
1624 if (prefix && exit_stat)
1625 snprintf(b, sizeof(b), "%s: ", prefix);
1626 else
1627 b[0] = '\0';
1628 switch(exit_stat) {
1629 case SG_LIB_CAT_CLEAN: /* 0 */
1630 break;
1631 case SG_LIB_SYNTAX_ERROR: /* 1 */
1632 print_p("%ssyntax error\n", b);
1633 break;
1634 case SG_LIB_CAT_NOT_READY: /* 2 */
1635 print_p("%sdevice not ready\n", b);
1636 break;
1637 case SG_LIB_CAT_MEDIUM_HARD: /* 3 */
1638 print_p("%smedium or hardware error\n", b);
1639 break;
1640 case SG_LIB_CAT_ILLEGAL_REQ: /* 5 */
1641 print_p("%sillegal request\n", b);
1642 break;
1643 case SG_LIB_CAT_UNIT_ATTENTION: /* 6 */
1644 print_p("%sunit attention\n", b);
1645 break;
1646 case SG_LIB_CAT_DATA_PROTECT: /* 7 */
1647 print_p("%sdata protect\n", b);
1648 break;
1649 case SG_LIB_CAT_INVALID_OP: /* 9 */
1650 print_p("%sinvalid opcode\n", b);
1651 break;
1652 case SG_LIB_CAT_COPY_ABORTED: /* 10 */
1653 print_p("%scopy aborted\n", b);
1654 break;
1655 case SG_LIB_CAT_ABORTED_COMMAND: /* 11 */
1656 print_p("%saborted command\n", b);
1657 break;
1658 case SG_LIB_CAT_MISCOMPARE: /* 14 */
1659 print_p("%smiscompare\n", b);
1660 break;
1661 case SG_LIB_FILE_ERROR: /* 15 */
1662 print_p("%sfile error\n", b);
1663 break;
1664 case SG_LIB_CAT_NO_SENSE: /* 20 */
1665 print_p("%sno sense (but possible warning/error)\n", b);
1666 break;
1667 case SG_LIB_CAT_RECOVERED: /* 21 */
1668 print_p("%srecovered error (possible future errors)\n", b);
1669 break;
1670 case SG_LIB_CAT_RES_CONFLICT: /* 24 */
1671 print_p("%sSCSI status: reservation conflict\n", b);
1672 break;
1673 case SG_LIB_CAT_TIMEOUT: /* 33 */
1674 print_p("%sSCSI command timeout\n", b);
1675 break;
1676 case SG_LIB_CAT_PROTECTION: /* 40 */
1677 print_p("%sprotection error\n", b);
1678 break;
1679 case SG_LIB_CAT_PROTECTION_WITH_INFO: /* 41 */
1680 print_p("%sprotection error with info\n", b);
1681 break;
1682 case DDPT_CAT_PARAM_LST_LEN_ERR: /* 50 */
1683 print_p("%sparameter list length error\n", b);
1684 break;
1685 case DDPT_CAT_INVALID_FLD_IN_PARAM: /* 51 */
1686 print_p("%sinvalid field in parameter list\n", b);
1687 break;
1688 case DDPT_CAT_TOO_MANY_SEGS_IN_PARAM: /* 52 */
1689 print_p("%stoo many segments in parameter list\n", b);
1690 break;
1691 case DDPT_CAT_TARGET_UNDERRUN: /* 53 */
1692 print_p("%starget underrun\n", b);
1693 break;
1694 case DDPT_CAT_TARGET_OVERRUN: /* 54 */
1695 print_p("%starget overrun\n", b);
1696 break;
1697 case DDPT_CAT_OP_IN_PROGRESS: /* 55 */
1698 print_p("%soperation in progress [list_id in use]\n", b);
1699 break;
1700 case DDPT_CAT_INSUFF_RES_CREATE_ROD: /* 56 */
1701 print_p("%sinsufficient resources to create ROD\n", b);
1702 break;
1703 case DDPT_CAT_INSUFF_RES_CREATE_RODTOK: /* 57 */
1704 print_p("%sinsufficient resources to create ROD Token\n", b);
1705 break;
1706 case DDPT_CAT_CMDS_CLEARED_BY_DEV_SVR: /* 58 */
1707 print_p("%scommands cleared by device servers\n", b);
1708 break;
1709 case SG_LIB_CAT_MALFORMED: /* 97 */
1710 print_p("%sresponse to SCSI command malformed\n", b);
1711 break;
1712 case SG_LIB_CAT_SENSE: /* 98 */
1713 print_p("%ssome other error/warning in sense data\n", b);
1714 break;
1715 case SG_LIB_CAT_OTHER: /* 99 */
1716 print_p("%ssome other error/warning, not sense data related\n", b);
1717 break;
1718 default:
1719 if ((exit_stat >= DDPT_CAT_TOKOP_BASE) &&
1720 (exit_stat < (DDPT_CAT_TOKOP_BASE + 20))) {
1721 print_p("%sinvalid token operation, ", b);
1722 switch (exit_stat - DDPT_CAT_TOKOP_BASE) { /* asc=0x23 */
1723 case 0: /* asc=0x23, asq=0x0 */
1724 print_p("cause not reportable\n");
1725 break;
1726 case 1: /* asc=0x23, asq=0x1 */
1727 print_p("unsupported token type\n");
1728 break;
1729 case 2:
1730 print_p("remote token usage not supported\n");
1731 break;
1732 case 3:
1733 print_p("remote ROD token creation not supported\n");
1734 break;
1735 case 4:
1736 print_p("token unknown\n");
1737 break;
1738 case 5:
1739 print_p("token corrupt\n");
1740 break;
1741 case 6:
1742 print_p("token revoked\n");
1743 break;
1744 case 7:
1745 print_p("token expired\n");
1746 break;
1747 case 8:
1748 print_p("token cancelled\n");
1749 break;
1750 case 9:
1751 print_p("token deleted\n");
1752 break;
1753 case 0xa:
1754 print_p("invalid token length\n");
1755 break;
1756 default:
1757 print_p("asc=0x23, asq=0x%x\n",
1758 exit_stat - DDPT_CAT_TOKOP_BASE);
1759 break;
1760 }
1761 } else {
1762 if (exit_stat >= 0)
1763 print_p("%sunexpected exit status value: %d [0x%x]\n", b,
1764 exit_stat, exit_stat);
1765 else
1766 print_p("%sunexpected exit status value: %d\n", b, exit_stat);
1767 }
1768 break;
1769 }
1770 }
1771
1772 /* Read numbers (up to 64 bits in size) from command line (comma (or
1773 * (single) space) separated list). Assumed decimal unless prefixed
1774 * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex).
1775 * Returns 0 if ok, or 1 if error. */
1776 int
cl_to_sgl(const char * inp,struct scat_gath_elem * sgl_arr,int * arr_len,int max_arr_len)1777 cl_to_sgl(const char * inp, struct scat_gath_elem * sgl_arr,
1778 int * arr_len, int max_arr_len)
1779 {
1780 int in_len, k;
1781 const char * lcp;
1782 int64_t ll;
1783 char * cp;
1784 char * c2p;
1785
1786 if ((NULL == inp) || (NULL == sgl_arr) ||
1787 (NULL == arr_len))
1788 return 1;
1789 lcp = inp;
1790 in_len = strlen(inp);
1791 if (0 == in_len)
1792 *arr_len = 0;
1793 if ('-' == inp[0]) { /* read from stdin */
1794 pr2serr("'--lba' cannot be read from stdin\n");
1795 return 1;
1796 } else { /* list of numbers (default decimal) on command line */
1797 k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, ");
1798 if (in_len != k) {
1799 pr2serr("cl_to_sgl: error at pos %d\n", k + 1);
1800 return 1;
1801 }
1802 for (k = 0; k < max_arr_len; ++k) {
1803 ll = sg_get_llnum(lcp);
1804 if (-1 != ll) {
1805 sgl_arr[k].lba = (uint64_t)ll;
1806 cp = (char *)strchr(lcp, ',');
1807 c2p = (char *)strchr(lcp, ' ');
1808 if (NULL == cp) {
1809 cp = c2p;
1810 if (NULL == cp)
1811 break;
1812 }
1813 if (c2p && (c2p < cp))
1814 cp = c2p;
1815 lcp = cp + 1;
1816 } else {
1817 pr2serr("cl_to_sgl: error at pos %d\n", (int)(lcp - inp + 1));
1818 return 1;
1819 }
1820 ll = sg_get_llnum(lcp);
1821 if (-1 != ll) {
1822 if (ll > UINT32_MAX) {
1823 pr2serr("cl_to_sgl: number exceeds 32 bits at pos %d\n",
1824 (int)(lcp - inp + 1));
1825 return 1;
1826 }
1827 sgl_arr[k].num = (uint32_t)ll;
1828 cp = (char *)strchr(lcp, ',');
1829 c2p = (char *)strchr(lcp, ' ');
1830 if (NULL == cp) {
1831 cp = c2p;
1832 if (NULL == cp)
1833 break;
1834 }
1835 if (c2p && (c2p < cp))
1836 cp = c2p;
1837 lcp = cp + 1;
1838 } else {
1839 pr2serr("cl_to_sgl: error at pos %d\n", (int)(lcp - inp + 1));
1840 return 1;
1841 }
1842 }
1843 *arr_len = k + 1;
1844 if (k == max_arr_len) {
1845 pr2serr("cl_to_sgl: array length exceeded\n");
1846 return 1;
1847 }
1848 }
1849 return 0;
1850 }
1851
1852 /* Read numbers from filename (or stdin) line by line (comma (or
1853 * (single) space) separated list). Assumed decimal unless prefixed
1854 * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex).
1855 * Returns 0 if ok, or 1 if error. */
1856 int
file_to_sgl(const char * file_name,struct scat_gath_elem * sgl_arr,int * arr_len,int max_arr_len)1857 file_to_sgl(const char * file_name, struct scat_gath_elem * sgl_arr,
1858 int * arr_len, int max_arr_len)
1859 {
1860 char line[1024];
1861 int off = 0;
1862 int in_len, k, j, m, have_stdin, ind, bit0;
1863 char * lcp;
1864 FILE * fp;
1865 int64_t ll;
1866
1867 have_stdin = ((1 == strlen(file_name)) && ('-' == file_name[0]));
1868 if (have_stdin)
1869 fp = stdin;
1870 else {
1871 fp = fopen(file_name, "r");
1872 if (NULL == fp) {
1873 pr2serr("file_to_sgl: unable to open %s\n", file_name);
1874 return 1;
1875 }
1876 }
1877
1878 for (j = 0; j < 512; ++j) {
1879 if (NULL == fgets(line, sizeof(line), fp))
1880 break;
1881 // could improve with carry_over logic if sizeof(line) too small
1882 in_len = strlen(line);
1883 if (in_len > 0) {
1884 if ('\n' == line[in_len - 1]) {
1885 --in_len;
1886 line[in_len] = '\0';
1887 }
1888 else {
1889 pr2serr("file_to_sgl: line too long, max %d bytes\n",
1890 (int)(sizeof(line) - 1));
1891 return 1;
1892 }
1893 }
1894 if (in_len < 1)
1895 continue;
1896 lcp = line;
1897 m = strspn(lcp, " \t");
1898 if (m == in_len)
1899 continue;
1900 lcp += m;
1901 in_len -= m;
1902 if ('#' == *lcp)
1903 continue;
1904 k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxXbBdDiIkKmMgGtTpP, \t");
1905 if ((k < in_len) && ('#' != lcp[k])) {
1906 pr2serr("file_to_sgl: syntax error at line %d, pos %d\n", j + 1,
1907 m + k + 1);
1908 return 1;
1909 }
1910 for (k = 0; k < 1024; ++k) {
1911 ll = sg_get_llnum(lcp);
1912 if (-1 != ll) {
1913 ind = ((off + k) >> 1);
1914 bit0 = 0x1 & (off + k);
1915 if (ind >= max_arr_len) {
1916 pr2serr("file_to_sgl: array length exceeded\n");
1917 return 1;
1918 }
1919 if (bit0) {
1920 if (ll > UINT32_MAX) {
1921 pr2serr("file_to_sgl: number exceeds 32 bits in "
1922 "line %d, at pos %d\n", j + 1,
1923 (int)(lcp - line + 1));
1924 return 1;
1925 }
1926 sgl_arr[ind].num = (uint32_t)ll;
1927 } else
1928 sgl_arr[ind].lba = (uint64_t)ll;
1929 lcp = strpbrk(lcp, " ,\t#");
1930 if ((NULL == lcp) || ('#' == *lcp))
1931 break;
1932 lcp += strspn(lcp, " ,\t");
1933 if ('\0' == *lcp)
1934 break;
1935 } else {
1936 if ('#' == *lcp) {
1937 --k;
1938 break;
1939 }
1940 pr2serr("file_to_sgl: error in line %d, at pos %d\n", j + 1,
1941 (int)(lcp - line + 1));
1942 return 1;
1943 }
1944 }
1945 off += (k + 1);
1946 }
1947 if (0x1 & off) {
1948 pr2serr("file_to_sgl: expect LBA,NUM pairs but decoded odd number\n"
1949 " from %s\n", have_stdin ? "stdin" : file_name);
1950 return 1;
1951 }
1952 *arr_len = off >> 1;
1953 return 0;
1954 }
1955