~ubuntu-branches/ubuntu/vivid/sg3-utils/vivid-proposed

« back to all changes in this revision

Viewing changes to src/sg_xcopy.c

  • Committer: Package Import Robot
  • Author(s): Ritesh Raj Sarraf
  • Date: 2013-06-23 16:08:01 UTC
  • mfrom: (1.2.7)
  • Revision ID: package-import@ubuntu.com-20130623160801-7rt7zb2dwk0ba7ut
Tags: 1.36-1
* [69e9dac] Imported Upstream version 1.36
* [cb75936] Add debian compat, level 7
* [68fed25] update README.source
* [3c724fc] Add build-dep autotools-dev
* [e4b9fdd] add destdir to install path
* [7cfff11] Simplify build with debhelper
* [f9a7540] Update symbols for 1.36 release
* [7b0b48d] Enable hardening build

Show diffs side-by-side

added added

removed removed

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