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, &sectorsize) */
540     if (ioctl(blk_fd, DIOCGSECTORSIZE, &sectorsize) < 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