1 /* A utility program for copying files. Similar to 'dd' but using
2 * the 'Extended Copy' command.
3 *
4 * Copyright (c) 2011-2022 Hannes Reinecke, SUSE Labs
5 *
6 * Largely taken from 'sg_dd', which has the
7 *
8 * Copyright (C) 1999 - 2010 D. Gilbert and P. Allworth
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * SPDX-License-Identifier: GPL-2.0-or-later
15 *
16 * This program is a specialisation of the Unix "dd" command in which
17 * either the input or the output file is a scsi generic device, raw
18 * device, a block device or a normal file. The block size ('bs') is
19 * assumed to be 512 if not given. This program complains if 'ibs' or
20 * 'obs' are given with a value that differs from 'bs' (or the default 512).
21 * If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is
22 * not given or 'of=-' then stdout assumed.
23 *
24 * A non-standard argument "bpt" (blocks per transfer) is added to control
25 * the maximum number of blocks in each transfer. The default value is 128.
26 * For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16 KiB
27 * in this case) is transferred to or from the sg device in a single SCSI
28 * command.
29 *
30 * This version is designed for the Linux kernel 2.4, 2.6, 3, 4 and 5 series.
31 */
32
33 #define _XOPEN_SOURCE 600
34 #ifndef _GNU_SOURCE
35 #define _GNU_SOURCE 1
36 #endif
37
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdbool.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <signal.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <limits.h>
49 #define __STDC_FORMAT_MACROS 1
50 #include <inttypes.h>
51 #include <sys/ioctl.h>
52 #include <sys/stat.h>
53 #include <sys/time.h>
54 #include <sys/file.h>
55 #include <sys/sysmacros.h>
56 #ifndef major
57 #include <sys/types.h>
58 #endif
59 #include <linux/major.h>
60
61 #ifdef HAVE_CONFIG_H
62 #include "config.h"
63 #endif
64
65 #include "sg_lib.h"
66 #include "sg_cmds_basic.h"
67 #include "sg_cmds_extra.h"
68 #include "sg_io_linux.h"
69 #include "sg_unaligned.h"
70 #include "sg_pr2serr.h"
71
72 static const char * version_str = "0.73 20220118";
73
74 #define ME "sg_xcopy: "
75
76 #define STR_SZ 1024
77 #define INOUTF_SZ 512
78 #define EBUFF_SZ 1024
79
80 #define DEF_BLOCK_SIZE 512
81 #define DEF_BLOCKS_PER_TRANSFER 128
82 #define MAX_BLOCKS_PER_TRANSFER 65535
83
84 #define DEF_MODE_RESP_LEN 252
85 #define RW_ERR_RECOVERY_MP 1
86 #define CACHING_MP 8
87 #define CONTROL_MP 0xa
88
89 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
90 #define READ_CAP_REPLY_LEN 8
91 #define RCAP16_REPLY_LEN 32
92
93 #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
94
95 #ifndef UINT32_MAX
96 #define UINT32_MAX ((uint32_t)-1)
97 #endif
98
99 #ifndef RAW_MAJOR
100 #define RAW_MAJOR 255 /*unlikely value */
101 #endif
102
103 #define SG_LIB_FLOCK_ERR 90
104
105 /* In SPC-4 the cdb opcodes have more generic names */
106 #define THIRD_PARTY_COPY_OUT_CMD 0x83
107 #define THIRD_PARTY_COPY_IN_CMD 0x84
108
109 /* Third party copy IN (opcode 0x84) and OUT (opcode 0x83) command service
110 * actions */
111 #define SA_XCOPY_LID1 0x0 /* OUT, originate */
112 #define SA_XCOPY_LID4 0x1 /* OUT, originate */
113 #define SA_POP_TOK 0x10 /* OUT, originate */
114 #define SA_WR_USING_TOK 0x11 /* OUT, originate */
115 #define SA_COPY_ABORT 0x1C /* OUT, abort */
116 #define SA_COPY_STATUS_LID1 0x0 /* IN, retrieve */
117 #define SA_COPY_DATA_LID1 0x1 /* IN, retrieve */
118 #define SA_COPY_OP_PARAMS 0x3 /* IN, retrieve */
119 #define SA_COPY_FAIL_DETAILS 0x4 /* IN, retrieve */
120 #define SA_COPY_STATUS_LID4 0x5 /* IN, retrieve */
121 #define SA_COPY_DATA_LID4 0x6 /* IN, retrieve */
122 #define SA_ROD_TOK_INFO 0x7 /* IN, retrieve */
123 #define SA_ALL_ROD_TOKS 0x8 /* IN, retrieve */
124
125 #define DEF_3PC_OUT_TIMEOUT (10 * 60) /* is 10 minutes enough? */
126 #define DEF_GROUP_NUM 0x0
127
128 #define VPD_DEVICE_ID 0x83
129 #define VPD_3PARTY_COPY 0x8f
130
131 #define FT_OTHER 1 /* filetype is probably normal */
132 #define FT_SG 2 /* filetype is sg or bsg char device */
133 #define FT_RAW 4 /* filetype is raw char device */
134 #define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */
135 #define FT_ST 16 /* filetype is st char device (tape) */
136 #define FT_BLOCK 32 /* filetype is block device */
137 #define FT_FIFO 64 /* filetype is a fifo (name pipe) */
138 #define FT_ERROR 128 /* couldn't "stat" file */
139
140 #define TD_FC_WWPN 1
141 #define TD_FC_PORT 2
142 #define TD_FC_WWPN_AND_PORT 4
143 #define TD_SPI 8
144 #define TD_VPD 16
145 #define TD_IPV4 32
146 #define TD_ALIAS 64
147 #define TD_RDMA 128
148 #define TD_FW 256
149 #define TD_SAS 512
150 #define TD_IPV6 1024
151 #define TD_IP_COPY_SERVICE 2048
152 #define TD_ROD 4096
153
154 #define XCOPY_TO_SRC "XCOPY_TO_SRC"
155 #define XCOPY_TO_DST "XCOPY_TO_DST"
156 #define DEF_XCOPY_SRC0_DST1 1
157
158 #define DEV_NULL_MINOR_NUM 3
159
160 #define MIN_RESERVED_SIZE 8192
161
162 #define MAX_UNIT_ATTENTIONS 10
163 #define MAX_ABORTED_CMDS 256
164
165 static int64_t dd_count = -1;
166 static int64_t in_full = 0;
167 static int in_partial = 0;
168 static int64_t out_full = 0;
169 static int out_partial = 0;
170
171 static bool do_time = false;
172 static bool start_tm_valid = false;
173 static bool xcopy_flag_cat = false;
174 static bool xcopy_flag_dc = false;
175 static bool xcopy_flag_fco = false; /* fast copy only, spc5r20 */
176 static int blk_sz = 0;
177 static int list_id_usage = -1;
178 static int priority = 1;
179 static int verbose = 0;
180 static struct timeval start_tm;
181
182
183 struct xcopy_fp_t {
184 bool append;
185 bool excl;
186 bool flock;
187 bool pad; /* Data descriptor PAD bit (residual data treatment) */
188 bool xcopy_given;
189 int sect_sz;
190 int sg_type, sg_fd;
191 int pdt; /* Peripheral device type */
192 dev_t devno;
193 uint32_t min_bytes;
194 uint32_t max_bytes;
195 int64_t num_sect;
196 char fname[INOUTF_SZ];
197 };
198
199 static struct xcopy_fp_t ixcf;
200 static struct xcopy_fp_t oxcf;
201
202 static const char * read_cap_str = "Read capacity";
203 static const char * rec_copy_op_params_str = "Receive copy operating "
204 "parameters";
205
206 static void calc_duration_throughput(int contin);
207
208
209 static void
install_handler(int sig_num,void (* sig_handler)(int sig))210 install_handler(int sig_num, void (*sig_handler) (int sig))
211 {
212 struct sigaction sigact;
213 sigaction (sig_num, NULL, &sigact);
214 if (sigact.sa_handler != SIG_IGN)
215 {
216 sigact.sa_handler = sig_handler;
217 sigemptyset (&sigact.sa_mask);
218 sigact.sa_flags = 0;
219 sigaction (sig_num, &sigact, NULL);
220 }
221 }
222
223 static void
print_stats(const char * str)224 print_stats(const char * str)
225 {
226 if (0 != dd_count)
227 pr2serr(" remaining block count=%" PRId64 "\n", dd_count);
228 pr2serr("%s%" PRId64 "+%d records in\n", str, in_full - in_partial,
229 in_partial);
230 pr2serr("%s%" PRId64 "+%d records out\n", str, out_full - out_partial,
231 out_partial);
232 }
233
234 static void
interrupt_handler(int sig)235 interrupt_handler(int sig)
236 {
237 struct sigaction sigact;
238
239 sigact.sa_handler = SIG_DFL;
240 sigemptyset(&sigact.sa_mask);
241 sigact.sa_flags = 0;
242 sigaction(sig, &sigact, NULL);
243 pr2serr("Interrupted by signal,");
244 if (do_time)
245 calc_duration_throughput(0);
246 print_stats("");
247 kill(getpid (), sig);
248 }
249
250 static void
siginfo_handler(int sig)251 siginfo_handler(int sig)
252 {
253 if (sig) { ; } /* unused, dummy to suppress warning */
254 pr2serr("Progress report, continuing ...\n");
255 if (do_time)
256 calc_duration_throughput(1);
257 print_stats(" ");
258 }
259
260 static bool bsg_major_checked = false;
261 static int bsg_major = 0;
262
263 static void
find_bsg_major(void)264 find_bsg_major(void)
265 {
266 const char * proc_devices = "/proc/devices";
267 FILE *fp;
268 char a[128];
269 char b[128];
270 char * cp;
271 int n;
272
273 if (NULL == (fp = fopen(proc_devices, "r"))) {
274 if (verbose)
275 pr2serr("fopen %s failed: %s\n", proc_devices, strerror(errno));
276 return;
277 }
278 while ((cp = fgets(b, sizeof(b), fp))) {
279 if ((1 == sscanf(b, "%126s", a)) &&
280 (0 == memcmp(a, "Character", 9)))
281 break;
282 }
283 while (cp && (cp = fgets(b, sizeof(b), fp))) {
284 if (2 == sscanf(b, "%d %126s", &n, a)) {
285 if (0 == strcmp("bsg", a)) {
286 bsg_major = n;
287 break;
288 }
289 } else
290 break;
291 }
292 if (verbose > 5) {
293 if (cp)
294 pr2serr("found bsg_major=%d\n", bsg_major);
295 else
296 pr2serr("found no bsg char device in %s\n", proc_devices);
297 }
298 fclose(fp);
299 }
300
301 /* Returns a file descriptor on success (0 or greater), -1 for an open
302 * error, -2 for a standard INQUIRY problem. */
303 static int
open_sg(struct xcopy_fp_t * fp,int vb)304 open_sg(struct xcopy_fp_t * fp, int vb)
305 {
306 int devmajor, devminor, offset;
307 struct sg_simple_inquiry_resp sir;
308 char ebuff[EBUFF_SZ];
309 int len, res;
310
311 devmajor = major(fp->devno);
312 devminor = minor(fp->devno);
313
314 if (fp->sg_type & FT_SG) {
315 snprintf(ebuff, EBUFF_SZ, "%.500s", fp->fname);
316 } else if (fp->sg_type & FT_BLOCK || fp->sg_type & FT_OTHER) {
317 int fd;
318
319 snprintf(ebuff, EBUFF_SZ, "/sys/dev/block/%d:%d/partition",
320 devmajor, devminor);
321 if ((fd = open(ebuff, O_RDONLY)) >= 0) {
322 ebuff[EBUFF_SZ - 1] = '\0';
323 len = read(fd, ebuff, EBUFF_SZ - 1);
324 if (len < 0) {
325 perror("read partition");
326 } else {
327 offset = strtoul(ebuff, NULL, 10);
328 devminor -= offset;
329 }
330 close(fd);
331 }
332 snprintf(ebuff, EBUFF_SZ, "/dev/block/%d:%d", devmajor, devminor);
333 } else {
334 snprintf(ebuff, EBUFF_SZ, "/dev/char/%d:%d", devmajor, devminor);
335 }
336 fp->sg_fd = sg_cmds_open_device(ebuff, false /* rw mode */, vb);
337 if (fp->sg_fd < 0) {
338 snprintf(ebuff, EBUFF_SZ,
339 ME "could not open %s device %d:%d for sg",
340 fp->sg_type & FT_BLOCK ? "block" : "char",
341 devmajor, devminor);
342 perror(ebuff);
343 return -sg_convert_errno(-fp->sg_fd);
344 }
345 if (sg_simple_inquiry(fp->sg_fd, &sir, false, vb)) {
346 pr2serr("INQUIRY failed on %s\n", ebuff);
347 res = sg_cmds_close_device(fp->sg_fd);
348 if (res < 0)
349 pr2serr("sg_cmds_close_device() failed as well\n");
350 fp->sg_fd = -1;
351 return -1;
352 }
353
354 fp->pdt = sir.peripheral_type;
355 if (vb)
356 pr2serr(" %s: %.8s %.16s %.4s [pdt=%d, 3pc=%d]\n", fp->fname,
357 sir.vendor, sir.product, sir.revision, fp->pdt,
358 !! (0x8 & sir.byte_5));
359
360 return fp->sg_fd;
361 }
362
363 static int
dd_filetype(struct xcopy_fp_t * fp)364 dd_filetype(struct xcopy_fp_t * fp)
365 {
366 struct stat st;
367 size_t len = strlen(fp->fname);
368
369 if ((1 == len) && ('.' == fp->fname[0]))
370 return FT_DEV_NULL;
371 if (stat(fp->fname, &st) < 0)
372 return FT_ERROR;
373 if (S_ISCHR(st.st_mode)) {
374 fp->devno = st.st_rdev;
375 /* major() and minor() defined in sys/sysmacros.h */
376 if ((MEM_MAJOR == major(st.st_rdev)) &&
377 (DEV_NULL_MINOR_NUM == minor(st.st_rdev)))
378 return FT_DEV_NULL;
379 if (RAW_MAJOR == major(st.st_rdev))
380 return FT_RAW;
381 if (SCSI_GENERIC_MAJOR == major(st.st_rdev))
382 return FT_SG;
383 if (SCSI_TAPE_MAJOR == major(st.st_rdev))
384 return FT_ST;
385 if (! bsg_major_checked) {
386 bsg_major_checked = true;
387 find_bsg_major();
388 }
389 if (bsg_major == (int)major(st.st_rdev))
390 return FT_SG;
391 } else if (S_ISBLK(st.st_mode)) {
392 fp->devno = st.st_rdev;
393 return FT_BLOCK;
394 } else if (S_ISFIFO(st.st_mode)) {
395 fp->devno = st.st_dev;
396 return FT_FIFO;
397 }
398 fp->devno = st.st_dev;
399 return FT_OTHER | FT_BLOCK;
400 }
401
402
403 static char *
dd_filetype_str(int ft,char * buff)404 dd_filetype_str(int ft, char * buff)
405 {
406 int off = 0;
407
408 if (FT_DEV_NULL & ft)
409 off += sg_scnpr(buff + off, 32, "null device ");
410 if (FT_SG & ft)
411 off += sg_scnpr(buff + off, 32, "SCSI generic (sg) device ");
412 if (FT_BLOCK & ft)
413 off += sg_scnpr(buff + off, 32, "block device ");
414 if (FT_FIFO & ft)
415 off += sg_scnpr(buff + off, 32, "fifo (named pipe) ");
416 if (FT_ST & ft)
417 off += sg_scnpr(buff + off, 32, "SCSI tape device ");
418 if (FT_RAW & ft)
419 off += sg_scnpr(buff + off, 32, "raw device ");
420 if (FT_OTHER & ft)
421 off += sg_scnpr(buff + off, 32, "other (perhaps ordinary file) ");
422 if (FT_ERROR & ft)
423 sg_scnpr(buff + off, 32, "unable to 'stat' file ");
424 return buff;
425 }
426
427 static int
simplified_ft(const struct xcopy_fp_t * xfp)428 simplified_ft(const struct xcopy_fp_t * xfp)
429 {
430 int ftype = xfp->sg_type;
431
432 switch (ftype) {
433 case FT_BLOCK:
434 case FT_ST:
435 case FT_OTHER: /* typically regular file */
436 case FT_DEV_NULL:
437 case FT_FIFO:
438 case FT_ERROR:
439 return ftype;
440 default:
441 if (FT_SG & ftype) {
442 if ((0 == xfp->pdt) || (0xe == xfp->pdt)) /* D-A or RBC */
443 return FT_BLOCK;
444 else if (0x1 == xfp->pdt)
445 return FT_ST;
446 }
447 return FT_OTHER;
448 }
449 }
450
451 static int
seg_desc_from_dd_type(int in_ft,int in_off,int out_ft,int out_off)452 seg_desc_from_dd_type(int in_ft, int in_off, int out_ft, int out_off)
453 {
454 int desc_type = -1;
455
456 switch (in_ft) {
457 case FT_BLOCK:
458 switch (out_ft) {
459 case FT_ST:
460 if (out_off)
461 break;
462
463 if (in_off)
464 desc_type = 0x8;
465 else
466 desc_type = 0;
467 break;
468 case FT_BLOCK:
469 if (in_off || out_off)
470 desc_type = 0xA;
471 else
472 desc_type = 2;
473 break;
474 default:
475 break;
476 }
477 break;
478 case FT_ST:
479 if (in_off)
480 break;
481
482 switch (out_ft) {
483 case FT_ST:
484 if (!out_off) {
485 desc_type = 3;
486 break;
487 }
488 break;
489 case FT_BLOCK:
490 if (out_off)
491 desc_type = 9;
492 else
493 desc_type = 3;
494 break;
495 case FT_DEV_NULL:
496 desc_type = 6;
497 break;
498 default:
499 break;
500 }
501 break;
502 default:
503 break;
504 }
505
506 return desc_type;
507 }
508
509 static void
usage(int n_help)510 usage(int n_help)
511 {
512 if (n_help < 2)
513 goto primary_help;
514 else
515 goto secondary_help;
516
517 primary_help:
518 pr2serr("Usage: "
519 "sg_xcopy [app=0|1] [bpt=BPT] [bs=BS] [cat=0|1] [conv=CONV]\n"
520 " [count=COUNT] [dc=0|1] [ibs=BS]\n"
521 " [id_usage=hold|discard|disable] [if=IFILE] "
522 "[iflag=FLAGS]\n"
523 " [list_id=ID] [obs=BS] [of=OFILE] "
524 "[oflag=FLAGS] [prio=PRIO]\n"
525 " [seek=SEEK] [skip=SKIP] [time=0|1] "
526 "[verbose=VERB]\n"
527 " [--help] [--on_dst|--on_src] [--verbose] "
528 "[--version]\n\n"
529 " where:\n"
530 " app if argument is 1 then open OFILE in append "
531 "mode\n"
532 " bpt is blocks_per_transfer (default: 128)\n"
533 " bs block size (default is 512)\n");
534 pr2serr(" cat xcopy segment descriptor CAT bit (default: "
535 "0)\n"
536 " conv ignored\n"
537 " count number of blocks to copy (def: device size)\n"
538 " dc xcopy segment descriptor DC bit (default: 0)\n"
539 " fco xcopy segment descriptor FCO bit (default: 0)\n"
540 " ibs input block size (if given must be same as "
541 "'bs=')\n"
542 " id_usage sets list_id_usage field to hold (0), "
543 "discard (2) or\n"
544 " disable (3)\n"
545 " if file or device to read from (def: stdin)\n"
546 " iflag comma separated list of flags applying to "
547 "IFILE\n"
548 " list_id sets list_id field to ID (default: 1 or 0)\n"
549 " obs output block size (if given must be same as "
550 "'bs=')\n"
551 " of file or device to write to (def: stdout), "
552 "OFILE of '.'\n");
553 pr2serr(" treated as /dev/null\n"
554 " oflag comma separated list of flags applying to "
555 "OFILE\n"
556 " prio set xcopy priority field to PRIO (def: 1)\n"
557 " seek block position to start writing to OFILE\n"
558 " skip block position to start reading from IFILE\n"
559 " time 0->no timing(def), 1->time plus calculate "
560 "throughput\n"
561 " verbose 0->quiet(def), 1->some noise, 2->more noise, "
562 "etc\n"
563 " --help|-h print out this usage message then exit\n"
564 " --on_dst send XCOPY command to OFILE\n"
565 " --on_src send XCOPY command to IFILE\n"
566 " --verbose|-v same action as verbose=1\n"
567 " --version|-V print version information then exit\n\n"
568 "Copy from IFILE to OFILE, similar to dd command; "
569 "but using the SCSI\nEXTENDED COPY (XCOPY(LID1)) command. For "
570 "list of flags, use '-hh'.\n");
571 return;
572
573 secondary_help:
574 pr2serr("FLAGS:\n"
575 " append (o) open OFILE in append mode\n"
576 " excl open corresponding device with O_EXCL\n"
577 " flock call flock(LOCK_EX|LOCK_NB)\n"
578 " null does nothing, placeholder\n"
579 " pad set xcopy data descriptor PAD bit on\n"
580 " corresponding device\n"
581 " xcopy send XCOPY command to corresponding device\n"
582 "\n"
583 "ENVIRONMENT VARIABLES:\n"
584 " XCOPY_TO_DST send XCOPY command to OFILE (destination) "
585 "if no other\n"
586 " indication\n"
587 " XCOPY_TO_SRC send XCOPY command to IFILE (source)\n"
588 );
589 }
590
591 static int
scsi_encode_seg_desc(uint8_t * seg_desc,int seg_desc_type,int64_t num_blk,uint64_t src_lba,uint64_t dst_lba)592 scsi_encode_seg_desc(uint8_t *seg_desc, int seg_desc_type,
593 int64_t num_blk, uint64_t src_lba, uint64_t dst_lba)
594 {
595 int seg_desc_len = 0;
596
597 seg_desc[0] = (uint8_t)seg_desc_type;
598 seg_desc[1] = 0x0;
599 if (xcopy_flag_cat)
600 seg_desc[1] |= 0x1;
601 if (xcopy_flag_dc)
602 seg_desc[1] |= 0x2;
603 if (xcopy_flag_fco)
604 seg_desc[1] |= 0x4;
605 if (seg_desc_type == 0x02) {
606 seg_desc_len = 0x18;
607 seg_desc[4] = 0;
608 seg_desc[5] = 0; /* Source target index */
609 seg_desc[7] = 1; /* Destination target index */
610 sg_put_unaligned_be16(num_blk, seg_desc + 10);
611 sg_put_unaligned_be64(src_lba, seg_desc + 12);
612 sg_put_unaligned_be64(dst_lba, seg_desc + 20);
613 }
614 sg_put_unaligned_be16(seg_desc_len, seg_desc + 2);
615 return seg_desc_len + 4;
616 }
617
618 static int
scsi_extended_copy(int sg_fd,uint8_t list_id,uint8_t * src_desc,int src_desc_len,uint8_t * dst_desc,int dst_desc_len,int seg_desc_type,int64_t num_blk,uint64_t src_lba,uint64_t dst_lba)619 scsi_extended_copy(int sg_fd, uint8_t list_id,
620 uint8_t *src_desc, int src_desc_len,
621 uint8_t *dst_desc, int dst_desc_len,
622 int seg_desc_type, int64_t num_blk,
623 uint64_t src_lba, uint64_t dst_lba)
624 {
625 uint8_t xcopyBuff[256];
626 int desc_offset = 16;
627 int seg_desc_len;
628 int verb, res;
629 char b[80];
630
631 verb = (verbose > 1) ? (verbose - 2) : 0;
632 memset(xcopyBuff, 0, 256);
633 xcopyBuff[0] = list_id;
634 xcopyBuff[1] = (list_id_usage << 3) | priority;
635 xcopyBuff[2] = 0;
636 xcopyBuff[3] = src_desc_len + dst_desc_len; /* Two target descriptors */
637 memcpy(xcopyBuff + desc_offset, src_desc, src_desc_len);
638 desc_offset += src_desc_len;
639 memcpy(xcopyBuff + desc_offset, dst_desc, dst_desc_len);
640 desc_offset += dst_desc_len;
641 seg_desc_len = scsi_encode_seg_desc(xcopyBuff + desc_offset,
642 seg_desc_type, num_blk,
643 src_lba, dst_lba);
644 xcopyBuff[11] = seg_desc_len; /* One segment descriptor */
645 desc_offset += seg_desc_len;
646 /* set noisy so if a UA happens it will be printed to stderr */
647 res = sg_ll_3party_copy_out(sg_fd, SA_XCOPY_LID1, list_id,
648 DEF_GROUP_NUM, DEF_3PC_OUT_TIMEOUT,
649 xcopyBuff, desc_offset, true, verb);
650 if (res) {
651 sg_get_category_sense_str(res, sizeof(b), b, verb);
652 pr2serr("Xcopy(LID1): %s\n", b);
653 }
654 return res;
655 }
656
657 /* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */
658 static int
scsi_read_capacity(struct xcopy_fp_t * xfp)659 scsi_read_capacity(struct xcopy_fp_t *xfp)
660 {
661 int res;
662 unsigned int ui;
663 uint8_t rcBuff[RCAP16_REPLY_LEN];
664 int verb;
665 char b[80];
666
667 verb = (verbose ? verbose - 1: 0);
668 res = sg_ll_readcap_10(xfp->sg_fd, false /* pmi */, 0, rcBuff,
669 READ_CAP_REPLY_LEN, true, verb);
670 if (0 != res) {
671 sg_get_category_sense_str(res, sizeof(b), b, verb);
672 pr2serr("Read capacity(10): %s\n", b);
673 return res;
674 }
675
676 if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) &&
677 (0xff == rcBuff[3])) {
678 uint64_t ls;
679
680 res = sg_ll_readcap_16(xfp->sg_fd, false /* pmi */, 0, rcBuff,
681 RCAP16_REPLY_LEN, true, verb);
682 if (0 != res) {
683 sg_get_category_sense_str(res, sizeof(b), b, verb);
684 pr2serr("Read capacity(16): %s\n", b);
685 return res;
686 }
687 ls = sg_get_unaligned_be64(rcBuff + 0);
688 xfp->num_sect = (int64_t)(ls + 1);
689 xfp->sect_sz = sg_get_unaligned_be32(rcBuff + 8);
690 } else {
691 ui = sg_get_unaligned_be32(rcBuff + 0);
692 /* take care not to sign extend values > 0x7fffffff */
693 xfp->num_sect = (int64_t)ui + 1;
694 xfp->sect_sz = sg_get_unaligned_be32(rcBuff + 4);
695 }
696 if (verbose)
697 pr2serr(" %s: number of blocks=%" PRId64 " [0x%" PRIx64 "], block "
698 "size=%d\n", xfp->fname, xfp->num_sect, xfp->num_sect,
699 xfp->sect_sz);
700 return 0;
701 }
702
703 static int
scsi_operating_parameter(struct xcopy_fp_t * xfp,int is_target)704 scsi_operating_parameter(struct xcopy_fp_t *xfp, int is_target)
705 {
706 bool valid = false;
707 int res, ftype, snlid, verb;
708 uint32_t rcBuffLen = 256, len, n, td_list = 0;
709 uint32_t num, max_target_num, max_segment_num, max_segment_len;
710 uint32_t max_desc_len, max_inline_data, held_data_limit;
711 uint8_t rcBuff[256];
712 char b[80];
713
714 verb = (verbose ? verbose - 1: 0);
715 ftype = xfp->sg_type;
716 if (FT_SG & ftype) {
717 if ((0 == xfp->pdt) || (0xe == xfp->pdt)) /* direct-access or RBC */
718 ftype |= FT_BLOCK;
719 else if (0x1 == xfp->pdt)
720 ftype |= FT_ST;
721 }
722 res = sg_ll_receive_copy_results(xfp->sg_fd, SA_COPY_OP_PARAMS, 0, rcBuff,
723 rcBuffLen, true, verb);
724 if (0 != res) {
725 sg_get_category_sense_str(res, sizeof(b), b, verb);
726 pr2serr("Xcopy operating parameters: %s\n", b);
727 return -res;
728 }
729
730 len = sg_get_unaligned_be32(rcBuff + 0);
731 if (len > rcBuffLen) {
732 pr2serr(" <<report len %d > %d too long for internal buffer, output "
733 "truncated\n", len, rcBuffLen);
734 }
735 if (verbose > 2) {
736 pr2serr("\nOutput response in hex:\n");
737 hex2stderr(rcBuff, len, 1);
738 }
739 snlid = rcBuff[4] & 0x1;
740 max_target_num = sg_get_unaligned_be16(rcBuff + 8);
741 max_segment_num = sg_get_unaligned_be16(rcBuff + 10);
742 max_desc_len = sg_get_unaligned_be32(rcBuff + 12);
743 max_segment_len = sg_get_unaligned_be32(rcBuff + 16);
744 xfp->max_bytes = max_segment_len ? max_segment_len : UINT32_MAX;
745 max_inline_data = sg_get_unaligned_be32(rcBuff + 20);
746 if (verbose) {
747 pr2serr(" >> %s response:\n", rec_copy_op_params_str);
748 pr2serr(" Support No List IDentifier (SNLID): %d\n", snlid);
749 pr2serr(" Maximum target descriptor count: %u\n",
750 (unsigned int)max_target_num);
751 pr2serr(" Maximum segment descriptor count: %u\n",
752 (unsigned int)max_segment_num);
753 pr2serr(" Maximum descriptor list length: %u\n",
754 (unsigned int)max_desc_len);
755 pr2serr(" Maximum segment length: %u\n",
756 (unsigned int)max_segment_len);
757 pr2serr(" Maximum inline data length: %u\n",
758 (unsigned int)max_inline_data);
759 }
760 held_data_limit = sg_get_unaligned_be32(rcBuff + 24);
761 if (list_id_usage < 0) {
762 if (!held_data_limit)
763 list_id_usage = 2;
764 else
765 list_id_usage = 0;
766 }
767 if (verbose) {
768 pr2serr(" Held data limit: %u (list_id_usage: %d)\n",
769 (unsigned int)held_data_limit, list_id_usage);
770 num = sg_get_unaligned_be32(rcBuff + 28);
771 pr2serr(" Maximum stream device transfer size: %u\n",
772 (unsigned int)num);
773 pr2serr(" Maximum concurrent copies: %u\n", rcBuff[36]);
774 if (rcBuff[37] > 30)
775 pr2serr(" Data segment granularity: 2**%u bytes\n",
776 rcBuff[37]);
777 else
778 pr2serr(" Data segment granularity: %u bytes\n",
779 1 << rcBuff[37]);
780 if (rcBuff[38] > 30)
781 pr2serr(" Inline data granularity: 2**%u bytes\n", rcBuff[38]);
782 else
783 pr2serr(" Inline data granularity: %u bytes\n",
784 1 << rcBuff[38]);
785 if (rcBuff[39] > 30)
786 pr2serr(" Held data granularity: 2**%u bytes\n",
787 1 << rcBuff[39]);
788 else
789 pr2serr(" Held data granularity: %u bytes\n", 1 << rcBuff[39]);
790
791 pr2serr(" Implemented descriptor list:\n");
792 }
793 xfp->min_bytes = 1 << rcBuff[37];
794
795 for (n = 0; n < rcBuff[43]; n++) {
796 switch(rcBuff[44 + n]) {
797 case 0x00: /* copy block to stream device */
798 if (!is_target && (ftype & FT_BLOCK))
799 valid = true;
800 if (is_target && (ftype & FT_ST))
801 valid = true;
802 if (verbose)
803 pr2serr(" Copy Block to Stream device\n");
804 break;
805 case 0x01: /* copy stream to block device */
806 if (!is_target && (ftype & FT_ST))
807 valid = true;
808 if (is_target && (ftype & FT_BLOCK))
809 valid = true;
810 if (verbose)
811 pr2serr(" Copy Stream to Block device\n");
812 break;
813 case 0x02: /* copy block to block device */
814 if (!is_target && (ftype & FT_BLOCK))
815 valid = true;
816 if (is_target && (ftype & FT_BLOCK))
817 valid = true;
818 if (verbose)
819 pr2serr(" Copy Block to Block device\n");
820 break;
821 case 0x03: /* copy stream to stream device */
822 if (!is_target && (ftype & FT_ST))
823 valid = true;
824 if (is_target && (ftype & FT_ST))
825 valid = true;
826 if (verbose)
827 pr2serr(" Copy Stream to Stream device\n");
828 break;
829 case 0x04: /* copy inline data to stream device */
830 if (!is_target && (ftype & FT_OTHER))
831 valid = true;
832 if (is_target && (ftype & FT_ST))
833 valid = true;
834 if (verbose)
835 pr2serr(" Copy inline data to Stream device\n");
836 break;
837 case 0x05: /* copy embedded data to stream device */
838 if (!is_target && (ftype & FT_OTHER))
839 valid = true;
840 if (is_target && (ftype & FT_ST))
841 valid = true;
842 if (verbose)
843 pr2serr(" Copy embedded data to Stream device\n");
844 break;
845 case 0x06: /* Read from stream device and discard */
846 if (!is_target && (ftype & FT_ST))
847 valid = true;
848 if (is_target && (ftype & FT_DEV_NULL))
849 valid = true;
850 if (verbose)
851 pr2serr(" Read from stream device and discard\n");
852 break;
853 case 0x07: /* Verify block or stream device operation */
854 if (!is_target && (ftype & (FT_ST | FT_BLOCK)))
855 valid = true;
856 if (is_target && (ftype & (FT_ST | FT_BLOCK)))
857 valid = true;
858 if (verbose)
859 pr2serr(" Verify block or stream device operation\n");
860 break;
861 case 0x08: /* copy block device with offset to stream device */
862 if (!is_target && (ftype & FT_BLOCK))
863 valid = true;
864 if (is_target && (ftype & FT_ST))
865 valid = true;
866 if (verbose)
867 pr2serr(" Copy block device with offset to stream "
868 "device\n");
869 break;
870 case 0x09: /* copy stream device to block device with offset */
871 if (!is_target && (ftype & FT_ST))
872 valid = true;
873 if (is_target && (ftype & FT_BLOCK))
874 valid = true;
875 if (verbose)
876 pr2serr(" Copy stream device to block device with "
877 "offset\n");
878 break;
879 case 0x0a: /* copy block device with offset to block device with
880 * offset */
881 if (!is_target && (ftype & FT_BLOCK))
882 valid = true;
883 if (is_target && (ftype & FT_BLOCK))
884 valid = true;
885 if (verbose)
886 pr2serr(" Copy block device with offset to block "
887 "device with offset\n");
888 break;
889 case 0x0b: /* copy block device to stream device and hold data */
890 if (!is_target && (ftype & FT_BLOCK))
891 valid = true;
892 if (is_target && (ftype & FT_ST))
893 valid = true;
894 if (verbose)
895 pr2serr(" Copy block device to stream device and hold "
896 "data\n");
897 break;
898 case 0x0c: /* copy stream device to block device and hold data */
899 if (!is_target && (ftype & FT_ST))
900 valid = true;
901 if (is_target && (ftype & FT_BLOCK))
902 valid = true;
903 if (verbose)
904 pr2serr(" Copy stream device to block device and hold "
905 "data\n");
906 break;
907 case 0x0d: /* copy block device to block device and hold data */
908 if (!is_target && (ftype & FT_BLOCK))
909 valid = true;
910 if (is_target && (ftype & FT_BLOCK))
911 valid = true;
912 if (verbose)
913 pr2serr(" Copy block device to block device and hold "
914 "data\n");
915 break;
916 case 0x0e: /* copy stream device to stream device and hold data */
917 if (!is_target && (ftype & FT_ST))
918 valid = true;
919 if (is_target && (ftype & FT_ST))
920 valid = true;
921 if (verbose)
922 pr2serr(" Copy block device to block device and hold "
923 "data\n");
924 break;
925 case 0x0f: /* read from stream device and hold data */
926 if (!is_target && (ftype & FT_ST))
927 valid = true;
928 if (is_target && (ftype & FT_DEV_NULL))
929 valid = true;
930 if (verbose)
931 pr2serr(" Read from stream device and hold data\n");
932 break;
933 case 0xe0: /* FC N_Port_Name */
934 if (verbose)
935 pr2serr(" FC N_Port_Name target descriptor\n");
936 td_list |= TD_FC_WWPN;
937 break;
938 case 0xe1: /* FC Port_ID */
939 if (verbose)
940 pr2serr(" FC Port_ID target descriptor\n");
941 td_list |= TD_FC_PORT;
942 break;
943 case 0xe2: /* FC N_Port_ID with N_Port_Name checking */
944 if (verbose)
945 pr2serr(" FC N_Port_ID with N_Port_Name target "
946 "descriptor\n");
947 td_list |= TD_FC_WWPN_AND_PORT;
948 break;
949 case 0xe3: /* Parallel Interface T_L */
950 if (verbose)
951 pr2serr(" SPI T_L target descriptor\n");
952 td_list |= TD_SPI;
953 break;
954 case 0xe4: /* identification descriptor */
955 if (verbose)
956 pr2serr(" Identification target descriptor\n");
957 td_list |= TD_VPD;
958 break;
959 case 0xe5: /* IPv4 */
960 if (verbose)
961 pr2serr(" IPv4 target descriptor\n");
962 td_list |= TD_IPV4;
963 break;
964 case 0xe6: /* Alias */
965 if (verbose)
966 pr2serr(" Alias target descriptor\n");
967 td_list |= TD_ALIAS;
968 break;
969 case 0xe7: /* RDMA */
970 if (verbose)
971 pr2serr(" RDMA target descriptor\n");
972 td_list |= TD_RDMA;
973 break;
974 case 0xe8: /* FireWire */
975 if (verbose)
976 pr2serr(" IEEE 1394 target descriptor\n");
977 td_list |= TD_FW;
978 break;
979 case 0xe9: /* SAS */
980 if (verbose)
981 pr2serr(" SAS target descriptor\n");
982 td_list |= TD_SAS;
983 break;
984 case 0xea: /* IPv6 */
985 if (verbose)
986 pr2serr(" IPv6 target descriptor\n");
987 td_list |= TD_IPV6;
988 break;
989 case 0xeb: /* IP Copy Service */
990 if (verbose)
991 pr2serr(" IP Copy Service target descriptor\n");
992 td_list |= TD_IP_COPY_SERVICE;
993 break;
994 case 0xfe: /* ROD */
995 if (verbose)
996 pr2serr(" ROD target descriptor\n");
997 td_list |= TD_ROD;
998 break;
999 default:
1000 pr2serr(">> Unhandled target descriptor 0x%02x\n",
1001 rcBuff[44 + n]);
1002 break;
1003 }
1004 }
1005 if (! valid) {
1006 pr2serr(">> no matching target descriptor supported\n");
1007 td_list = 0;
1008 }
1009 return td_list;
1010 }
1011
1012 static void
decode_designation_descriptor(const uint8_t * bp,int i_len)1013 decode_designation_descriptor(const uint8_t * bp, int i_len)
1014 {
1015 char c[2048];
1016
1017 sg_get_designation_descriptor_str(NULL, bp, i_len, 1, verbose,
1018 sizeof(c), c);
1019 pr2serr("%s", c);
1020 }
1021
1022 static int
desc_from_vpd_id(int sg_fd,uint8_t * desc,int desc_len,unsigned int block_size,bool pad)1023 desc_from_vpd_id(int sg_fd, uint8_t *desc, int desc_len,
1024 unsigned int block_size, bool pad)
1025 {
1026 int res, verb;
1027 uint8_t rcBuff[256], *bp, *best = NULL;
1028 unsigned int len = 254;
1029 int off = -1, i_len, best_len = 0, assoc, desig, f_desig = 0;
1030 char b[80];
1031
1032 verb = (verbose ? verbose - 1: 0);
1033 memset(rcBuff, 0xff, len);
1034 res = sg_ll_inquiry(sg_fd, false, true /* evpd */, VPD_DEVICE_ID, rcBuff,
1035 4, true, verb);
1036 if (0 != res) {
1037 if (SG_LIB_CAT_ILLEGAL_REQ == res)
1038 pr2serr("Device identification VPD page not found\n");
1039 else {
1040 sg_get_category_sense_str(res, sizeof(b), b, verbose);
1041 pr2serr("VPD inquiry (Device ID): %s\n", b);
1042 pr2serr(" try again with '-vv'\n");
1043 }
1044 return res;
1045 } else if (rcBuff[1] != VPD_DEVICE_ID) {
1046 pr2serr("invalid VPD response\n");
1047 return SG_LIB_CAT_MALFORMED;
1048 }
1049 len = sg_get_unaligned_be16(rcBuff + 2) + 4;
1050 res = sg_ll_inquiry(sg_fd, false, true, VPD_DEVICE_ID, rcBuff, len, true,
1051 verb);
1052 if (0 != res) {
1053 sg_get_category_sense_str(res, sizeof(b), b, verbose);
1054 pr2serr("VPD inquiry (Device ID): %s\n", b);
1055 return res;
1056 } else if (rcBuff[1] != VPD_DEVICE_ID) {
1057 pr2serr("invalid VPD response\n");
1058 return SG_LIB_CAT_MALFORMED;
1059 }
1060 if (verbose > 2) {
1061 pr2serr("Output response in hex:\n");
1062 hex2stderr(rcBuff, len, 1);
1063 }
1064
1065 while (sg_vpd_dev_id_iter(rcBuff + 4, len - 4, &off, 0, -1, -1) == 0) {
1066 bp = rcBuff + 4 + off;
1067 i_len = bp[3];
1068 if (((unsigned int)off + i_len + 4) > len) {
1069 pr2serr(" VPD page error: designator length %d longer "
1070 "than\n remaining response length=%d\n", i_len,
1071 (len - off));
1072 return SG_LIB_CAT_MALFORMED;
1073 }
1074 assoc = ((bp[1] >> 4) & 0x3);
1075 desig = (bp[1] & 0xf);
1076 if (verbose > 2)
1077 pr2serr(" Desc %d: assoc %u desig %u len %d\n", off, assoc,
1078 desig, i_len);
1079 /* Identification descriptor's Designator length must be <= 20. */
1080 if (i_len > 20)
1081 continue;
1082 if (desig == /*NAA=*/3) {
1083 best = bp;
1084 best_len = i_len;
1085 break;
1086 }
1087 if (desig == /*EUI64=*/2) {
1088 if (!best || f_desig < 2) {
1089 best = bp;
1090 best_len = i_len;
1091 f_desig = 2;
1092 }
1093 } else if (desig == /*T10*/1) {
1094 if (!best || f_desig == 0) {
1095 best = bp;
1096 best_len = i_len;
1097 f_desig = desig;
1098 }
1099 } else if (desig == /*vend.spec.=*/0) {
1100 if (!best) {
1101 best = bp;
1102 best_len = i_len;
1103 f_desig = desig;
1104 }
1105 }
1106 }
1107 if (best) {
1108 if (verbose)
1109 decode_designation_descriptor(best, best_len);
1110 if (best_len + 4 < desc_len) {
1111 memset(desc, 0, 32);
1112 desc[0] = 0xe4; /* Identification Descriptor */
1113 memcpy(desc + 4, best, best_len + 4);
1114 desc[4] &= 0x0f; /* code set */
1115 desc[5] &= 0x3f; /* association and designator type */
1116 if (pad)
1117 desc[28] = 0x4;
1118 sg_put_unaligned_be24((uint32_t)block_size, desc + 29);
1119 if (verbose > 3) {
1120 pr2serr("Descriptor in hex (bs %d):\n", block_size);
1121 hex2stderr(desc, 32, 1);
1122 }
1123 return 32;
1124 }
1125 return best_len + 8;
1126 }
1127 return 0;
1128 }
1129
1130 static void
calc_duration_throughput(int contin)1131 calc_duration_throughput(int contin)
1132 {
1133 struct timeval end_tm, res_tm;
1134 double a, b;
1135 int64_t blks;
1136
1137 if (start_tm_valid && (start_tm.tv_sec || start_tm.tv_usec)) {
1138 blks = (in_full > out_full) ? in_full : out_full;
1139 gettimeofday(&end_tm, NULL);
1140 res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
1141 res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
1142 if (res_tm.tv_usec < 0) {
1143 --res_tm.tv_sec;
1144 res_tm.tv_usec += 1000000;
1145 }
1146 a = res_tm.tv_sec;
1147 a += (0.000001 * res_tm.tv_usec);
1148 b = (double)blk_sz * blks;
1149 pr2serr("time to transfer data%s: %d.%06d secs",
1150 (contin ? " so far" : ""), (int)res_tm.tv_sec,
1151 (int)res_tm.tv_usec);
1152 if ((a > 0.00001) && (b > 511))
1153 pr2serr(" at %.2f MB/sec\n", b / (a * 1000000.0));
1154 else
1155 pr2serr("\n");
1156 }
1157 }
1158
1159 /* Process arguments given to 'iflag=" or 'oflag=" options. Returns 0
1160 * on success, 1 on error. */
1161 static int
process_flags(const char * arg,struct xcopy_fp_t * fp)1162 process_flags(const char * arg, struct xcopy_fp_t * fp)
1163 {
1164 char buff[256];
1165 char * cp;
1166 char * np;
1167
1168 strncpy(buff, arg, sizeof(buff) - 1);
1169 buff[sizeof(buff) - 1] = '\0';
1170 if ('\0' == buff[0]) {
1171 pr2serr("no flag found\n");
1172 return 1;
1173 }
1174 cp = buff;
1175 do {
1176 np = strchr(cp, ',');
1177 if (np)
1178 *np++ = '\0';
1179 if (0 == strcmp(cp, "append"))
1180 fp->append = true;
1181 else if (0 == strcmp(cp, "excl"))
1182 fp->excl = true;
1183 else if (0 == strcmp(cp, "flock"))
1184 fp->flock = true;
1185 else if (0 == strcmp(cp, "null"))
1186 ;
1187 else if (0 == strcmp(cp, "pad"))
1188 fp->pad = true;
1189 else if (0 == strcmp(cp, "xcopy"))
1190 fp->xcopy_given = true; /* for ddpt compatibility */
1191 else {
1192 pr2serr("unrecognised flag: %s\n", cp);
1193 return 1;
1194 }
1195 cp = np;
1196 } while (cp);
1197 return 0;
1198 }
1199
1200 /* Returns open input file descriptor (>= 0) or a negative value
1201 * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error.
1202 */
1203 static int
open_if(struct xcopy_fp_t * ifp,int vb)1204 open_if(struct xcopy_fp_t * ifp, int vb)
1205 {
1206 int infd = -1, flags, fl, res, err;
1207 char ebuff[EBUFF_SZ];
1208
1209 ifp->sg_type = dd_filetype(ifp);
1210
1211 if (vb)
1212 pr2serr(" >> Input file type: %s, devno %d:%d\n",
1213 dd_filetype_str(ifp->sg_type, ebuff),
1214 major(ifp->devno), minor(ifp->devno));
1215 if (FT_ERROR & ifp->sg_type) {
1216 pr2serr(ME "unable access %s\n", ifp->fname);
1217 return -SG_LIB_FILE_ERROR;
1218 }
1219 flags = O_NONBLOCK;
1220 if (ifp->excl)
1221 flags |= O_EXCL;
1222 fl = O_RDWR;
1223 if ((infd = open(ifp->fname, fl | flags)) < 0) {
1224 fl = O_RDONLY;
1225 if ((infd = open(ifp->fname, fl | flags)) < 0) {
1226 err = errno;
1227 snprintf(ebuff, EBUFF_SZ,
1228 ME "could not open %.500s for sg reading", ifp->fname);
1229 perror(ebuff);
1230 return -sg_convert_errno(err);
1231 }
1232 }
1233 if (vb)
1234 pr2serr(" open input(sg_io), flags=0x%x\n", fl | flags);
1235
1236 if (ifp->flock) {
1237 res = flock(infd, LOCK_EX | LOCK_NB);
1238 if (res < 0) {
1239 close(infd);
1240 snprintf(ebuff, EBUFF_SZ, ME "flock(LOCK_EX | LOCK_NB) on %.500s "
1241 "failed", ifp->fname);
1242 perror(ebuff);
1243 return -SG_LIB_FLOCK_ERR;
1244 }
1245 }
1246 return infd;
1247 }
1248
1249 /* Returns open output file descriptor (>= 0), -1 for don't
1250 * bother opening (e.g. /dev/null), or a more negative value
1251 * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error.
1252 */
1253 static int
open_of(struct xcopy_fp_t * ofp,int vb)1254 open_of(struct xcopy_fp_t * ofp, int vb)
1255 {
1256 int outfd, flags, res, err;
1257 char ebuff[EBUFF_SZ];
1258
1259 ofp->sg_type = dd_filetype(ofp);
1260 if (vb)
1261 pr2serr(" >> Output file type: %s, devno %d:%d\n",
1262 dd_filetype_str(ofp->sg_type, ebuff),
1263 major(ofp->devno), minor(ofp->devno));
1264
1265 if (!(FT_DEV_NULL & ofp->sg_type)) {
1266 flags = O_RDWR | O_NONBLOCK;
1267 if (ofp->excl)
1268 flags |= O_EXCL;
1269 if (ofp->append)
1270 flags |= O_APPEND;
1271 if ((outfd = open(ofp->fname, flags)) < 0) {
1272 err = errno;
1273 snprintf(ebuff, EBUFF_SZ,
1274 ME "could not open %.500s for sg writing", ofp->fname);
1275 perror(ebuff);
1276 return -sg_convert_errno(err);
1277 }
1278 if (vb)
1279 pr2serr(" open output(sg_io), flags=0x%x\n", flags);
1280 } else
1281 outfd = -1; /* don't bother opening */
1282 if ((outfd >= 0) && ofp->flock) {
1283 res = flock(outfd, LOCK_EX | LOCK_NB);
1284 if (res < 0) {
1285 close(outfd);
1286 snprintf(ebuff, EBUFF_SZ, ME "flock(LOCK_EX | LOCK_NB) on %.500s "
1287 "failed", ofp->fname);
1288 perror(ebuff);
1289 return -SG_LIB_FLOCK_ERR;
1290 }
1291 }
1292 return outfd;
1293 }
1294
1295 static int
num_chs_in_str(const char * s,int slen,int ch)1296 num_chs_in_str(const char * s, int slen, int ch)
1297 {
1298 int res = 0;
1299
1300 while (--slen >= 0) {
1301 if (ch == s[slen])
1302 ++res;
1303 }
1304 return res;
1305 }
1306
1307
1308 int
main(int argc,char * argv[])1309 main(int argc, char * argv[])
1310 {
1311 bool bpt_given = false;
1312 bool list_id_given = false;
1313 bool on_src = false;
1314 bool on_src_dst_given = false;
1315 bool verbose_given = false;
1316 bool version_given = false;
1317 int res, k, n, keylen, infd, outfd, xcopy_fd;
1318 int blocks = 0;
1319 int bpt = DEF_BLOCKS_PER_TRANSFER;
1320 int dst_desc_len;
1321 int ibs = 0;
1322 int num_help = 0;
1323 int num_xcopy = 0;
1324 int obs = 0;
1325 int ret = 0;
1326 int seg_desc_type;
1327 int src_desc_len;
1328 int64_t skip = 0;
1329 int64_t seek = 0;
1330 uint8_t list_id = 1;
1331 char * key;
1332 char * buf;
1333 char str[STR_SZ];
1334 uint8_t src_desc[256];
1335 uint8_t dst_desc[256];
1336
1337 ixcf.fname[0] = '\0';
1338 oxcf.fname[0] = '\0';
1339 ixcf.num_sect = -1;
1340 oxcf.num_sect = -1;
1341
1342 if (argc < 2) {
1343 pr2serr("Won't default both IFILE to stdin _and_ OFILE to stdout\n");
1344 pr2serr("For more information use '--help'\n");
1345 return SG_LIB_CONTRADICT;
1346 }
1347
1348 for (k = 1; k < argc; k++) {
1349 if (argv[k]) {
1350 strncpy(str, argv[k], STR_SZ - 1);
1351 str[STR_SZ - 1] = '\0';
1352 } else
1353 continue;
1354 for (key = str, buf = key; *buf && *buf != '=';)
1355 buf++;
1356 if (*buf)
1357 *buf++ = '\0';
1358 keylen = (int)strlen(key);
1359 if (0 == strncmp(key, "app", 3)) {
1360 ixcf.append = !! sg_get_num(buf);
1361 oxcf.append = ixcf.append;
1362 } else if (0 == strcmp(key, "bpt")) {
1363 bpt = sg_get_num(buf);
1364 if (-1 == bpt) {
1365 pr2serr(ME "bad argument to 'bpt='\n");
1366 return SG_LIB_SYNTAX_ERROR;
1367 }
1368 bpt_given = true;
1369 } else if (0 == strcmp(key, "bs")) {
1370 blk_sz = sg_get_num(buf);
1371 if (-1 == blk_sz) {
1372 pr2serr(ME "bad argument to 'bs='\n");
1373 return SG_LIB_SYNTAX_ERROR;
1374 }
1375 } else if (0 == strcmp(key, "list_id")) {
1376 ret = sg_get_num(buf);
1377 if (-1 == ret || ret > 0xff) {
1378 pr2serr(ME "bad argument to 'list_id='\n");
1379 return SG_LIB_SYNTAX_ERROR;
1380 }
1381 list_id = (ret & 0xff);
1382 list_id_given = true;
1383 } else if (0 == strcmp(key, "id_usage")) {
1384 if (!strncmp(buf, "hold", 4))
1385 list_id_usage = 0;
1386 else if (!strncmp(buf, "discard", 7))
1387 list_id_usage = 2;
1388 else if (!strncmp(buf, "disable", 7))
1389 list_id_usage = 3;
1390 else {
1391 pr2serr(ME "bad argument to 'id_usage='\n");
1392 return SG_LIB_SYNTAX_ERROR;
1393 }
1394 } else if (0 == strcmp(key, "conv"))
1395 pr2serr(ME ">>> ignoring all 'conv=' arguments\n");
1396 else if (0 == strcmp(key, "count")) {
1397 if (0 != strcmp("-1", buf)) {
1398 dd_count = sg_get_llnum(buf);
1399 if (-1LL == dd_count) {
1400 pr2serr(ME "bad argument to 'count='\n");
1401 return SG_LIB_SYNTAX_ERROR;
1402 }
1403 } /* treat 'count=-1' as calculate count (same as not given) */
1404 } else if (0 == strcmp(key, "prio")) {
1405 priority = sg_get_num(buf);
1406 } else if (0 == strcmp(key, "cat")) {
1407 n = sg_get_num(buf);
1408 if (n < 0 || n > 1) {
1409 pr2serr(ME "bad argument to 'cat='\n");
1410 return SG_LIB_SYNTAX_ERROR;
1411 }
1412 xcopy_flag_cat = !! n;
1413 } else if (0 == strcmp(key, "dc")) {
1414 n = sg_get_num(buf);
1415 if (n < 0 || n > 1) {
1416 pr2serr(ME "bad argument to 'dc='\n");
1417 return SG_LIB_SYNTAX_ERROR;
1418 }
1419 xcopy_flag_dc = !! n;
1420 } else if (0 == strcmp(key, "fco")) {
1421 n = sg_get_num(buf);
1422 if (n < 0 || n > 1) {
1423 pr2serr(ME "bad argument to 'fco='\n");
1424 return SG_LIB_SYNTAX_ERROR;
1425 }
1426 xcopy_flag_fco = !! n;
1427 } else if (0 == strcmp(key, "ibs")) {
1428 ibs = sg_get_num(buf);
1429 } else if (strcmp(key, "if") == 0) {
1430 if ('\0' != ixcf.fname[0]) {
1431 pr2serr("Second IFILE argument??\n");
1432 return SG_LIB_CONTRADICT;
1433 } else {
1434 memcpy(ixcf.fname, buf, INOUTF_SZ - 1);
1435 ixcf.fname[INOUTF_SZ - 1] = '\0';
1436 }
1437 } else if (0 == strcmp(key, "iflag")) {
1438 if (process_flags(buf, &ixcf)) {
1439 pr2serr(ME "bad argument to 'iflag='\n");
1440 return SG_LIB_SYNTAX_ERROR;
1441 }
1442 } else if (0 == strcmp(key, "obs")) {
1443 obs = sg_get_num(buf);
1444 } else if (strcmp(key, "of") == 0) {
1445 if ('\0' != oxcf.fname[0]) {
1446 pr2serr("Second OFILE argument??\n");
1447 return SG_LIB_CONTRADICT;
1448 } else {
1449 memcpy(oxcf.fname, buf, INOUTF_SZ - 1);
1450 oxcf.fname[INOUTF_SZ - 1] = '\0';
1451 }
1452 } else if (0 == strcmp(key, "oflag")) {
1453 if (process_flags(buf, &oxcf)) {
1454 pr2serr(ME "bad argument to 'oflag='\n");
1455 return SG_LIB_SYNTAX_ERROR;
1456 }
1457 } else if (0 == strcmp(key, "seek")) {
1458 seek = sg_get_llnum(buf);
1459 if (-1LL == seek) {
1460 pr2serr(ME "bad argument to 'seek='\n");
1461 return SG_LIB_SYNTAX_ERROR;
1462 }
1463 } else if (0 == strcmp(key, "skip")) {
1464 skip = sg_get_llnum(buf);
1465 if (-1LL == skip) {
1466 pr2serr(ME "bad argument to 'skip='\n");
1467 return SG_LIB_SYNTAX_ERROR;
1468 }
1469 } else if (0 == strcmp(key, "time"))
1470 do_time = !! sg_get_num(buf);
1471 else if (0 == strncmp(key, "verb", 4))
1472 verbose = sg_get_num(buf);
1473 /* look for long options that start with '--' */
1474 else if (0 == strncmp(key, "--help", 6))
1475 ++num_help;
1476 else if (0 == strncmp(key, "--on_dst", 8)) {
1477 on_src = false;
1478 if (on_src_dst_given) {
1479 pr2serr("Syntax error - either specify --on_src OR "
1480 "--on_dst\n");
1481 pr2serr("For more information use '--help'\n");
1482 return SG_LIB_CONTRADICT;
1483 }
1484 on_src_dst_given = true;
1485 } else if (0 == strncmp(key, "--on_src", 8)) {
1486 on_src = true;
1487 if (on_src_dst_given) {
1488 pr2serr("Syntax error - either specify --on_src OR "
1489 "--on_dst\n");
1490 pr2serr("For more information use '--help'\n");
1491 return SG_LIB_CONTRADICT;
1492 }
1493 on_src_dst_given = true;
1494 } else if (0 == strncmp(key, "--verb", 6)) {
1495 verbose_given = true;
1496 verbose += 1;
1497 } else if (0 == strncmp(key, "--vers", 6))
1498 version_given = true;
1499 else if (0 == strncmp(key, "--xcopy", 7))
1500 ; /* ignore; for compatibility with ddpt */
1501 /* look for short options that start with a single '-', they can be
1502 * concaternated (e.g. '-vvvV') */
1503 else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
1504 res = 0;
1505 n = num_chs_in_str(key + 1, keylen - 1, 'h');
1506 num_help += n;
1507 res += n;
1508 n = num_chs_in_str(key + 1, keylen - 1, 'v');
1509 verbose += n;
1510 if (n > 0)
1511 verbose_given = true;
1512 res += n;
1513 n = num_chs_in_str(key + 1, keylen - 1, 'V');
1514 if (n > 0)
1515 version_given = true;
1516 res += n;
1517 n = num_chs_in_str(key + 1, keylen - 1, 'x');
1518 /* accept and ignore; for compatibility with ddpt */
1519 res += n;
1520 if (res < (keylen - 1)) {
1521 pr2serr(ME "Unrecognised short option in '%s', try "
1522 "'--help'\n", key);
1523 if (0 == num_help)
1524 return -1;
1525 }
1526 } else {
1527 pr2serr("Unrecognized option '%s'\n", key);
1528 if (num_help)
1529 usage(num_help);
1530 else
1531 pr2serr("For more information use '--help'\n");
1532 return SG_LIB_SYNTAX_ERROR;
1533 }
1534 }
1535 if (num_help) {
1536 usage(num_help);
1537 return 0;
1538 }
1539 #ifdef DEBUG
1540 pr2serr("In DEBUG mode, ");
1541 if (verbose_given && version_given) {
1542 pr2serr("but override: '-vV' given, zero verbose and continue\n");
1543 verbose_given = false;
1544 version_given = false;
1545 verbose = 0;
1546 } else if (! verbose_given) {
1547 pr2serr("set '-vv'\n");
1548 verbose = 2;
1549 } else
1550 pr2serr("keep verbose=%d\n", verbose);
1551 #else
1552 if (verbose_given && version_given)
1553 pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
1554 #endif
1555 if (version_given) {
1556 pr2serr(ME "%s\n", version_str);
1557 return 0;
1558 }
1559
1560 if (! on_src_dst_given) {
1561 if (ixcf.xcopy_given == oxcf.xcopy_given) {
1562 char * csp;
1563 char * cdp;
1564
1565 csp = getenv(XCOPY_TO_SRC);
1566 cdp = getenv(XCOPY_TO_DST);
1567 if ((!! csp) == (!! cdp)) {
1568 #if DEF_XCOPY_SRC0_DST1 == 0
1569 on_src = true;
1570 #else
1571 on_src = false;
1572 #endif
1573 } else if (csp)
1574 on_src = true;
1575 else
1576 on_src = false;
1577 } else if (ixcf.xcopy_given)
1578 on_src = true;
1579 else
1580 on_src = false;
1581 }
1582 if (verbose > 1)
1583 pr2serr(" >>> Extended Copy(LID1) command will be sent to %s device "
1584 "[%s]\n", (on_src ? "src" : "dst"),
1585 (on_src ? ixcf.fname : oxcf.fname));
1586
1587 if ((ibs && blk_sz && (ibs != blk_sz)) ||
1588 (obs && blk_sz && (obs != blk_sz))) {
1589 pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
1590 pr2serr("For more information use '--help'\n");
1591 return SG_LIB_CONTRADICT;
1592 }
1593 if (blk_sz && !ibs)
1594 ibs = blk_sz;
1595 if (blk_sz && !obs)
1596 obs = blk_sz;
1597
1598 if ((skip < 0) || (seek < 0)) {
1599 pr2serr("skip and seek cannot be negative\n");
1600 return SG_LIB_CONTRADICT;
1601 }
1602 if (oxcf.append && (seek > 0)) {
1603 pr2serr("Can't use both append and seek switches\n");
1604 return SG_LIB_CONTRADICT;
1605 }
1606 if (bpt < 1) {
1607 pr2serr("bpt must be greater than 0\n");
1608 return SG_LIB_SYNTAX_ERROR;
1609 } else if (bpt > MAX_BLOCKS_PER_TRANSFER) {
1610 pr2serr("bpt must be less than or equal to %d\n",
1611 MAX_BLOCKS_PER_TRANSFER);
1612 return SG_LIB_SYNTAX_ERROR;
1613 }
1614 if (list_id_usage == 3) { /* list_id usage disabled */
1615 if (! list_id_given)
1616 list_id = 0;
1617 if (list_id) {
1618 pr2serr("list_id disabled by id_usage flag\n");
1619 return SG_LIB_SYNTAX_ERROR;
1620 }
1621 }
1622
1623 if (verbose > 1)
1624 pr2serr(" >>> " ME " if=%s skip=%" PRId64 " of=%s seek=%" PRId64
1625 " count=%" PRId64 "\n", ixcf.fname, skip, oxcf.fname, seek,
1626 dd_count);
1627 install_handler(SIGINT, interrupt_handler);
1628 install_handler(SIGQUIT, interrupt_handler);
1629 install_handler(SIGPIPE, interrupt_handler);
1630 install_handler(SIGUSR1, siginfo_handler);
1631
1632 ixcf.pdt = -1;
1633 oxcf.pdt = -1;
1634 if (ixcf.fname[0] && ('-' != ixcf.fname[0])) {
1635 infd = open_if(&ixcf, verbose);
1636 if (infd < 0)
1637 return -infd;
1638 } else {
1639 pr2serr("stdin not acceptable for IFILE\n");
1640 return SG_LIB_FILE_ERROR;
1641 }
1642
1643 if (oxcf.fname[0] && ('-' != oxcf.fname[0])) {
1644 outfd = open_of(&oxcf, verbose);
1645 if (outfd < -1)
1646 return -outfd;
1647 } else {
1648 pr2serr("stdout not acceptable for OFILE\n");
1649 return SG_LIB_FILE_ERROR;
1650 }
1651
1652 res = open_sg(&ixcf, verbose);
1653 if (res < 0) {
1654 if (-1 == res)
1655 return SG_LIB_FILE_ERROR;
1656 else
1657 return SG_LIB_CAT_OTHER;
1658 }
1659 res = open_sg(&oxcf, verbose);
1660 if (res < 0) {
1661 if (-1 == res)
1662 return SG_LIB_FILE_ERROR;
1663 else
1664 return SG_LIB_CAT_OTHER;
1665 }
1666
1667 if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) {
1668 pr2serr("Can't have both 'if' as stdin _and_ 'of' as stdout\n");
1669 pr2serr("For more information use '--help'\n");
1670 return SG_LIB_CONTRADICT;
1671 }
1672
1673 res = scsi_read_capacity(&ixcf);
1674 if (SG_LIB_CAT_UNIT_ATTENTION == res) {
1675 pr2serr("Unit attention (%s in), continuing\n", read_cap_str);
1676 res = scsi_read_capacity(&ixcf);
1677 } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
1678 pr2serr("Aborted command (%s in), continuing\n", read_cap_str);
1679 res = scsi_read_capacity(&ixcf);
1680 }
1681 if (0 != res) {
1682 if (res == SG_LIB_CAT_INVALID_OP)
1683 pr2serr("%s command not supported on %s\n", read_cap_str,
1684 ixcf.fname);
1685 else if (res == SG_LIB_CAT_NOT_READY)
1686 pr2serr("%s failed on %s - not ready\n", read_cap_str,
1687 ixcf.fname);
1688 else
1689 pr2serr("Unable to %s on %s\n", read_cap_str, ixcf.fname);
1690 ixcf.num_sect = -1;
1691 } else if (ibs && ixcf.sect_sz != ibs) {
1692 pr2serr(">> warning: block size on %s confusion: "
1693 "ibs=%d, device claims=%d\n", ixcf.fname, ibs, ixcf.sect_sz);
1694 }
1695 if (skip && ixcf.num_sect < skip) {
1696 pr2serr("argument to 'skip=' exceeds device size (max %" PRId64 ")\n",
1697 ixcf.num_sect);
1698 return SG_LIB_SYNTAX_ERROR;
1699 }
1700
1701 res = scsi_read_capacity(&oxcf);
1702 if (SG_LIB_CAT_UNIT_ATTENTION == res) {
1703 pr2serr("Unit attention (%s out), continuing\n", read_cap_str);
1704 res = scsi_read_capacity(&oxcf);
1705 } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
1706 pr2serr("Aborted command (%s out), continuing\n", read_cap_str);
1707 res = scsi_read_capacity(&oxcf);
1708 }
1709 if (0 != res) {
1710 if (res == SG_LIB_CAT_INVALID_OP)
1711 pr2serr("%s command not supported on %s\n", read_cap_str,
1712 oxcf.fname);
1713 else
1714 pr2serr("Unable to %s on %s\n", read_cap_str, oxcf.fname);
1715 oxcf.num_sect = -1;
1716 } else if (obs && obs != oxcf.sect_sz) {
1717 pr2serr(">> warning: block size on %s confusion: obs=%d, device "
1718 "claims=%d\n", oxcf.fname, obs, oxcf.sect_sz);
1719 }
1720 if (seek && oxcf.num_sect < seek) {
1721 pr2serr("argument to 'seek=' exceeds device size (max %" PRId64 ")\n",
1722 oxcf.num_sect);
1723 return SG_LIB_SYNTAX_ERROR;
1724 }
1725 if ((dd_count < 0) || ((verbose > 0) && (0 == dd_count))) {
1726 if (xcopy_flag_dc == 0) {
1727 dd_count = ixcf.num_sect - skip;
1728 if ((dd_count * ixcf.sect_sz) >
1729 ((oxcf.num_sect - seek) * oxcf.sect_sz))
1730 dd_count = (oxcf.num_sect - seek) * oxcf.sect_sz /
1731 ixcf.sect_sz;
1732 } else {
1733 dd_count = oxcf.num_sect - seek;
1734 if ((dd_count * oxcf.sect_sz) >
1735 ((ixcf.num_sect - skip) * ixcf.sect_sz))
1736 dd_count = (ixcf.num_sect - skip) * ixcf.sect_sz /
1737 oxcf.sect_sz;
1738 }
1739 } else {
1740 int64_t dd_bytes;
1741
1742 if (xcopy_flag_dc)
1743 dd_bytes = dd_count * oxcf.sect_sz;
1744 else
1745 dd_bytes = dd_count * ixcf.sect_sz;
1746
1747 if (dd_bytes > ixcf.num_sect * ixcf.sect_sz) {
1748 pr2serr("access beyond end of source device (max %" PRId64 ")\n",
1749 ixcf.num_sect);
1750 return SG_LIB_SYNTAX_ERROR;
1751 }
1752 if (dd_bytes > oxcf.num_sect * oxcf.sect_sz) {
1753 pr2serr("access beyond end of target device (max %" PRId64 ")\n",
1754 oxcf.num_sect);
1755 return SG_LIB_SYNTAX_ERROR;
1756 }
1757 }
1758
1759 res = scsi_operating_parameter(&ixcf, 0);
1760 if (res < 0) {
1761 if (SG_LIB_CAT_UNIT_ATTENTION == -res) {
1762 pr2serr("Unit attention (%s), continuing\n",
1763 rec_copy_op_params_str);
1764 res = scsi_operating_parameter(&ixcf, 0);
1765 }
1766 if (-res == SG_LIB_CAT_INVALID_OP) {
1767 pr2serr("%s command not supported on %s\n",
1768 rec_copy_op_params_str, ixcf.fname);
1769 ret = sg_convert_errno(EINVAL);
1770 goto fini;
1771 } else if (-res == SG_LIB_CAT_NOT_READY)
1772 pr2serr("%s failed on %s - not ready\n",
1773 rec_copy_op_params_str, ixcf.fname);
1774 else {
1775 pr2serr("Unable to %s on %s\n", rec_copy_op_params_str,
1776 ixcf.fname);
1777 ret = -res;
1778 goto fini;
1779 }
1780 } else if (res == 0) {
1781 ret = SG_LIB_CAT_INVALID_OP;
1782 goto fini;
1783 }
1784
1785 if (res & TD_VPD) {
1786 if (verbose)
1787 pr2serr(" >> using VPD identification for source %s\n",
1788 ixcf.fname);
1789 src_desc_len = desc_from_vpd_id(ixcf.sg_fd, src_desc,
1790 sizeof(src_desc), ixcf.sect_sz, ixcf.pad);
1791 if (src_desc_len > (int)sizeof(src_desc)) {
1792 pr2serr("source descriptor too large (%d bytes)\n", res);
1793 ret = SG_LIB_CAT_MALFORMED;
1794 goto fini;
1795 }
1796 } else {
1797 ret = SG_LIB_CAT_INVALID_OP;
1798 goto fini;
1799 }
1800
1801 res = scsi_operating_parameter(&oxcf, 1);
1802 if (res < 0) {
1803 if (SG_LIB_CAT_UNIT_ATTENTION == -res) {
1804 pr2serr("Unit attention (%s), continuing\n",
1805 rec_copy_op_params_str);
1806 res = scsi_operating_parameter(&oxcf, 1);
1807 }
1808 if (-res == SG_LIB_CAT_INVALID_OP) {
1809 pr2serr("%s command not supported on %s\n",
1810 rec_copy_op_params_str, oxcf.fname);
1811 ret = sg_convert_errno(EINVAL);
1812 goto fini;
1813 } else if (-res == SG_LIB_CAT_NOT_READY)
1814 pr2serr("%s failed on %s - not ready\n",
1815 rec_copy_op_params_str, oxcf.fname);
1816 else {
1817 pr2serr("Unable to %s on %s\n", rec_copy_op_params_str,
1818 oxcf.fname);
1819 ret = -res;
1820 goto fini;
1821 }
1822 } else if (res == 0) {
1823 ret = SG_LIB_CAT_INVALID_OP;
1824 goto fini;
1825 }
1826
1827 if (res & TD_VPD) {
1828 if (verbose)
1829 pr2serr(" >> using VPD identification for destination %s\n",
1830 oxcf.fname);
1831 dst_desc_len = desc_from_vpd_id(oxcf.sg_fd, dst_desc,
1832 sizeof(dst_desc), oxcf.sect_sz, oxcf.pad);
1833 if (dst_desc_len > (int)sizeof(dst_desc)) {
1834 pr2serr("destination descriptor too large (%d bytes)\n", res);
1835 ret = SG_LIB_CAT_MALFORMED;
1836 goto fini;
1837 }
1838 } else {
1839 ret = SG_LIB_CAT_INVALID_OP;
1840 goto fini;
1841 }
1842
1843 if (dd_count < 0) {
1844 pr2serr("Couldn't calculate count, please give one\n");
1845 return SG_LIB_CAT_OTHER;
1846 }
1847
1848 if (dd_count < (ixcf.min_bytes / (uint32_t)ixcf.sect_sz)) {
1849 pr2serr("not enough data to read (min %" PRIu32 " bytes)\n",
1850 oxcf.min_bytes);
1851 return SG_LIB_CAT_OTHER;
1852 }
1853 if (dd_count < (oxcf.min_bytes / (uint32_t)oxcf.sect_sz)) {
1854 pr2serr("not enough data to write (min %" PRIu32 " bytes)\n",
1855 oxcf.min_bytes);
1856 return SG_LIB_CAT_OTHER;
1857 }
1858
1859 if (bpt_given) {
1860 if (xcopy_flag_dc) {
1861 if ((uint32_t)(bpt * oxcf.sect_sz) > oxcf.max_bytes) {
1862 pr2serr("bpt too large (max %" PRIu32 " blocks)\n",
1863 oxcf.max_bytes / (uint32_t)oxcf.sect_sz);
1864 return SG_LIB_SYNTAX_ERROR;
1865 }
1866 } else {
1867 if ((uint32_t)(bpt * ixcf.sect_sz) > ixcf.max_bytes) {
1868 pr2serr("bpt too large (max %" PRIu32 " blocks)\n",
1869 ixcf.max_bytes / (uint32_t)ixcf.sect_sz);
1870 return SG_LIB_SYNTAX_ERROR;
1871 }
1872 }
1873 } else {
1874 uint32_t r;
1875
1876 if (xcopy_flag_dc)
1877 r = oxcf.max_bytes / (uint32_t)oxcf.sect_sz;
1878 else
1879 r = ixcf.max_bytes / (uint32_t)ixcf.sect_sz;
1880 bpt = (r > MAX_BLOCKS_PER_TRANSFER) ? MAX_BLOCKS_PER_TRANSFER : r;
1881 }
1882
1883 seg_desc_type = seg_desc_from_dd_type(simplified_ft(&ixcf), 0,
1884 simplified_ft(&oxcf), 0);
1885
1886 if (do_time) {
1887 start_tm.tv_sec = 0;
1888 start_tm.tv_usec = 0;
1889 gettimeofday(&start_tm, NULL);
1890 start_tm_valid = true;
1891 }
1892
1893 if (verbose)
1894 pr2serr("Start of loop, count=%" PRId64 ", bpt=%d, lba_in=%" PRId64
1895 ", lba_out=%" PRId64 "\n", dd_count, bpt, skip, seek);
1896
1897 xcopy_fd = (on_src) ? infd : outfd;
1898
1899 while (dd_count > 0) {
1900 if (dd_count > bpt)
1901 blocks = bpt;
1902 else
1903 blocks = dd_count;
1904 res = scsi_extended_copy(xcopy_fd, list_id, src_desc, src_desc_len,
1905 dst_desc, dst_desc_len, seg_desc_type,
1906 blocks, skip, seek);
1907 if (res != 0)
1908 break;
1909 in_full += blocks;
1910 skip += blocks;
1911 seek += blocks;
1912 dd_count -= blocks;
1913 num_xcopy++;
1914 }
1915
1916 if (do_time)
1917 calc_duration_throughput(0);
1918 if (res)
1919 pr2serr("sg_xcopy: failed with error %d (%" PRId64 " blocks left)\n",
1920 res, dd_count);
1921 else
1922 pr2serr("sg_xcopy: %" PRId64 " blocks, %d command%s\n", in_full,
1923 num_xcopy, ((num_xcopy > 1) ? "s" : ""));
1924 ret = res;
1925
1926 fini:
1927 /* file handles not explicitly closed; let process cleanup do that */
1928 if (0 == verbose) {
1929 if (! sg_if_can2stderr("sg_xcopy failed: ", ret))
1930 pr2serr("Some error occurred, try again with '-v' or '-vv' for "
1931 "more information\n");
1932 }
1933 return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
1934 }
1935