sg_xcopy: add environment variables: XCOPY_TO_SRC and XCOPY_TO_DST; sg_rtpg: fix indexing bug with --extended option

git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@537 6180dd3e-e324-4e3e-922d-17de1ae2f315
diff --git a/COVERAGE b/COVERAGE
index 290eaf0..8b13a1e 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -8,12 +8,12 @@
 ------------        -------------------------------------------------
 ATA COMMAND PASS-THROUGH(16)  sg_sat_identify, sg_sat_set_features,
                     sg_sat_phy_event, ++
-		    [sg_sat_chk_power, sg__sat_identify,
-		     sg__sat_set_features, sg_sat_smart_rd_data
-		     (previous four in the examples directory)]
+                    [sg_sat_chk_power, sg__sat_identify,
+                     sg__sat_set_features, sg_sat_smart_rd_data
+                     (previous four in the examples directory)]
 ATA COMMAND PASS-THROUGH(12)  sg_sat_identify, ++
 COMPARE AND WRITE   sg_compare_and_write
-EXTENDED COPY       sg_xcopy, ++
+EXTENDED COPY(LID1)    sg_xcopy, ++
 GET CONFIGURATION   sg_get_config, ++
 GET LBA STATUS      sg_get_lba_status, ++
 INQUIRY             sg_dd, sg_format, sg_inq, sginfo,
@@ -43,11 +43,14 @@
 READ CAPACITY(16)   sg_readcap, sg_dd, sgm_dd, sgp_dd, sg_format, ++
 READ DEFECT(10)     sginfo('-d' or '-G'), sg_reassign('-g'), smartmontools, ++
 READ DEFECT(12)     sginfo('-d' or '-G'), smartmontools
-READ LONG (10)      sg_read_long, sg_dd, ++
-READ LONG (16)      sg_read_long, ++
+READ LONG(10)       sg_read_long, sg_dd, ++
+READ LONG(16)       sg_read_long, ++
 READ MEDIA SERIAL NUMBER     sg_rmsn, ++
 REASSIGN BLOCKS     sg_reassign, ++
-RECEIVE COPY RESULTS   sg_copy_results, ++
+RECEIVE COPY DATA(LID1)    sg_copy_results, ++
+RECEIVE COPY FAILURE DETAILS(LID1)    sg_copy_results, ++
+RECEIVE COPY OPERATING PARAMETERS    sg_copy_results, sg_xcopy, ++
+RECEIVE COPY STATUS(LID1)    sg_copy_results, ++
 RECEIVE DIAGNOSTIC RESULTS  sg_senddiag, sg_ses, ++
 REPORT IDENTIFYING INFORMATION  sg_ident, ++ (2)
 REPORT LUNS         sg_luns, ++
@@ -99,6 +102,10 @@
 (2) this command was known as REPORT DEVICE IDENTIFIER prior to spc4r07
 (3) this command was known as SET DEVICE IDENTIFIER prior to spc4r07
 
+The RECEIVE COPY * commands in SPC-4 were grouped as one command name
+with 4 service actions in SPC-3 and earlier. The single SPC-3 command
+name is RECEIVE COPY RESULTS.
+
 
 Douglas Gilbert
-2nd December 2013
+10th December 2013
diff --git a/ChangeLog b/ChangeLog
index 62f7eaf..2aa9f53 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@
 some description at the top of its ".c" file. All utilities in the main
 directory have their own "man" pages. There is also a sg3_utils man page.
 
-Changelog for sg3_utils-1.38 [20131202] [svn: r536]
+Changelog for sg3_utils-1.38 [20131214] [svn: r537]
   - sg_ses: add --dev-slot-num= and --sas-addr=
     - error and warning message cleanup
   - sg_inq: add --block=0|1 option to control opens
@@ -10,8 +10,11 @@
     - sync version descriptors dated 20131126
     - fix overflow in encode_whitespaces
   - sg_vpd: add LU_CONG to standard inquiry response output
+  - sg_xcopy: environment variables: XCOPY_TO_SRC and
+    XCOPY_TO_DST indicate where xcopy command is sent
   - sg_luns: guard against garbage response
   - sg_write_same: repeat if unit attention
+  - sg_rtpg: fix indexing bug with --extended option
   - sg_lib_data: sync asc/ascq codes with T10 dated 20131110
   - examples: add sg_tst_excl3 for testing O_EXCL
     - improve sg_tst_excl and sg_tst_excl2
diff --git a/README b/README
index 1d29b64..f3fc752 100644
--- a/README
+++ b/README
@@ -401,4 +401,4 @@
 
 
 Douglas Gilbert
-1st December 2013
+11th December 2013
diff --git a/debian/changelog b/debian/changelog
index 96665db..1b84117 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@
 
   * New upstream version
 
- -- Douglas Gilbert <[email protected]>  Sun, 01 Dec 2013 05:00:00 +0100
+ -- Douglas Gilbert <[email protected]>  Wed, 11 Dec 2013 01:00:00 +0100
 
 sg3-utils (1.37-0.1) unstable; urgency=low
 
diff --git a/doc/sg_copy_results.8 b/doc/sg_copy_results.8
index c891417..7ee22fd 100644
--- a/doc/sg_copy_results.8
+++ b/doc/sg_copy_results.8
@@ -1,4 +1,4 @@
-.TH SG_COPY_RESULTS "8" "June 2012" "sg3_utils\-1.37" SG3_UTILS
+.TH SG_COPY_RESULTS "8" "December 2013" "sg3_utils\-1.38" SG3_UTILS
 .SH NAME
 sg_copy_results \- send SCSI RECEIVE COPY RESULTS command (XCOPY related)
 .SH SYNOPSIS
@@ -25,20 +25,20 @@
 The command has four distinct modes of operation, distinguished by
 the service action field:
 .TP
-\fBCOPY STATUS\fR
+\fBCOPY STATUS  [SPC\-4: RECEIVE COPY STATUS(LID1)]\fR
 Displays the current status of the EXTENDED COPY command identified by
 the list id field.
 .TP
-\fBRECEIVE DATA\fR
+\fBRECEIVE DATA  [SPC\-4: RECEIVE COPY DATA(LID1)]\fR
 Return the held data read by the EXTENDED COPY command identified by
 the list id field. This option is only meaningful if the respective
 segment descriptor are supported.
 .TP
-\fBOPERATING PARAMETERS\fR
+\fBOPERATING PARAMETERS  [SPC\-4: RECEIVE COPY OPERATING PARAMETERS]\fR
 Return copy manager operating parameters. This option is also useful
 to determine if the SCSI Extended Copy facility is supported.
 .TP
-\fBFAILED SEGMENT DETAILS\fR
+\fBFAILED SEGMENT DETAILS  [SPC\-4: RECEIVE COPY FAILURE DETAILS(LID1)]\fR
 Return copy target device sense data and other information about any
 failed segments.
 
diff --git a/doc/sg_xcopy.8 b/doc/sg_xcopy.8
index 883f729..123816f 100644
--- a/doc/sg_xcopy.8
+++ b/doc/sg_xcopy.8
@@ -1,4 +1,4 @@
-.TH SG_XCOPY "8" "October 2013" "sg3_utils\-1.37" SG3_UTILS
+.TH SG_XCOPY "8" "December 2013" "sg3_utils\-1.38" SG3_UTILS
 .SH NAME
 sg_xcopy \- copy data to and from files and devices using SCSI EXTENDED
 COPY (XCOPY)
@@ -37,9 +37,10 @@
 operands. The second group are extra options added by this utility.
 Both groups are defined below in combined, alphabetical order.
 .PP
-By default the XCOPY command is sent to \fIIFILE\fR. This can be changed
-with the \fI\-\-on_dst\fR option which causes the XCOPY command to be sent
-to \fIOFILE\fR instead.
+By default the XCOPY command is sent to \fIOFILE\fR. This can be changed
+with the \fI\-\-on_src\fR or \fIiflag=xflag\R options which cause the XCOPY
+command to be sent to \fIIFILE\fR instead. Also see the section on
+ENVIRONMENT VARIABLES.
 .SH OPTIONS
 .TP
 \fBbpt\fR=\fIBPT\fR
@@ -157,11 +158,12 @@
 outputs usage message and exits.
 .TP
 \fB\-\-on_dst\fR
-send the XCOPY command to the output file/device.
+send the XCOPY command to the output file/device (i.e. \fIOFILE\fR). This is
+the default unless overridden by the \fI\-\-on_src\fR or \fIiflag=xflag\fR
+options. Also see the section below on ENVIRONMENT VARIABLES.
 .TP
 \fB\-\-on_src\fR
-send the XCOPY command to the input file/device. This is the default when
-this option and \fI\-\-on_dst\fR are not given.
+send the XCOPY command to the input file/device (i.e. \fIIFILE\fR).
 .TP
 \fB\-v\fR, \fB\-\-verbose\fR
 equivalent to \fIverbose=1\fR. When used twice, equivalent to
@@ -231,6 +233,14 @@
 If the \fIpad\fR bit is set for both source and target any residual
 source data will be discarded, and any residual destination data will
 be padded.
+.SH ENVIRONMENT VARIABLES
+If the command line invocation does not explicitly (and unambiguously)
+indicate whether the XCOPY SCSI command should be sent to \fIIFILE\fR (i.e.
+the source) or \fIOFILE\fR (i.e. the destination) then a check is
+made for the presence of the XCOPY_TO_SRC and XCOPY_TO_DST environment
+variables. If either one exists (but not both) then it indicates where
+the SCSI XCOPY command will be sent. By default the XCOPY command is
+sent to \fIOFILE\fR.
 .SH RETIRED OPTIONS
 Here are some retired options that are still present:
 .TP
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 85f1081..216ae99 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -79,7 +79,7 @@
 %{_libdir}/*.la
 
 %changelog
-* Sun Dec 01 2013 - dgilbert at interlog dot com
+* Wed Dec 11 2013 - dgilbert at interlog dot com
 - track t10 changes
   * sg3_utils-1.38
 
diff --git a/src/sg_rtpg.c b/src/sg_rtpg.c
index c13b231..94129b0 100644
--- a/src/sg_rtpg.c
+++ b/src/sg_rtpg.c
@@ -26,7 +26,7 @@
  * to the given SCSI device.
  */
 
-static const char * version_str = "1.17 20130507";
+static const char * version_str = "1.18 20131214";
 
 #define REPORT_TGT_GRP_BUFF_LEN 1024
 
@@ -251,9 +251,10 @@
                   goto err_out;
              }
              printf("  Implicit transition time: %d\n", ucp[1]);
-             ucp += 4;;
+             ucp += 4;
         }
-        for (k = 4; k < report_len; k += off, ucp += off) {
+        for (k = ucp - reportTgtGrpBuff; k < report_len;
+             k += off, ucp += off) {
 
             printf("  target port group id : 0x%x , Pref=%d\n",
                    (ucp[2] << 8) + ucp[3], !!(ucp[0] & 0x80));
diff --git a/src/sg_xcopy.c b/src/sg_xcopy.c
index 17f0bff..307a4fc 100644
--- a/src/sg_xcopy.c
+++ b/src/sg_xcopy.c
@@ -62,7 +62,7 @@
 #include "sg_cmds_extra.h"
 #include "sg_io_linux.h"
 
-static const char * version_str = "0.39 20131006";
+static const char * version_str = "0.40 20131214";
 
 #define ME "sg_xcopy: "
 
@@ -114,6 +114,10 @@
 #define TD_IP_COPY_SERVICE 2048
 #define TD_ROD 4096
 
+#define XCOPY_TO_SRC "XCOPY_TO_SRC"
+#define XCOPY_TO_DST "XCOPY_TO_DST"
+#define DEF_XCOPY_SRC0_DST1 1
+
 #define DEV_NULL_MINOR_NUM 3
 
 #define MIN_RESERVED_SIZE 8192
@@ -126,11 +130,6 @@
 static int in_partial = 0;
 static int64_t out_full = 0;
 static int out_partial = 0;
-#if 0
-static int recovered_errs = 0;
-static int unrecovered_errs = 0;
-static int num_retries = 0;
-#endif
 
 static int do_time = 0;
 static int verbose = 0;
@@ -157,9 +156,7 @@
     int flock;
     int pad;     /* Data descriptor PAD bit (residual data treatment) */
     int pdt;     /* Peripheral device type */
-#if 0
-    int retries;
-#endif
+    int xcopy_given;
 };
 
 static struct xcopy_fp_t ixcf;
@@ -210,15 +207,6 @@
             in_partial);
     pr2serr("%s%" PRId64 "+%d records out\n", str, out_full - out_partial,
             out_partial);
-#if 0
-    if (recovered_errs > 0)
-        pr2serr("%s%d recovered errors\n", str, recovered_errs);
-    if (num_retries > 0)
-        pr2serr("%s%d retries attempted\n", str, num_retries);
-    else if (unrecovered_errs)
-        pr2serr("%s%d unrecovered error(s)\n", str,
-                unrecovered_errs);
-#endif
 }
 
 
@@ -494,43 +482,48 @@
 }
 
 static void
-usage()
+usage(int n_help)
 {
+    if (n_help < 2)
+        goto primary_help;
+    else
+        goto secondary_help;
+
+primary_help:
     pr2serr("Usage: "
-            "sg_xcopy  [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]"
-            " [iflag=FLAGS]\n"
-            "                 [obs=BS] [of=OFILE] [oflag=FLAGS] "
-            "[seek=SEEK] [skip=SKIP]\n"
-            "                 [--help] [--version]\n\n"
-            "                 [bpt=BPT] [cat=0|1] [dc=0|1] "
-            "[id_usage=hold|discard|disable]\n"
-            "                 [list_id=ID] [prio=PRIO] [time=0|1] "
-            "[verbose=VERB]\n"
-            "                 [--on_dst|--on_src] [--verbose]\n"
+            "sg_xcopy  [bpt=BPT] [bs=BS] [cat=0|1] [count=COUNT] [dc=0|1] "
+            "[ibs=BS]\n"
+            "                 [id_usage=hold|discard|disable] [if=IFILE] "
+            "[iflag=FLAGS]\n"
+            "                 [list_id=ID] [obs=BS] [of=OFILE] [oflag=FLAGS] "
+            "[prio=PRIO]\n"
+            "                 [seek=SEEK] [skip=SKIP] [time=0|1] "
+            "[verbose=VERB] [--help]\n"
+            "                 [--on_dst|--on_src] [--verbose] [--version]\n\n"
             "  where:\n"
             "    bpt         is blocks_per_transfer (default: 128)\n"
             "    bs          block size (default is 512)\n");
-    pr2serr("    cat         segment descriptor CAT bit (default: 0)\n"
+    pr2serr("    cat         xcopy segment descriptor CAT bit (default: "
+            "0)\n"
             "    count       number of blocks to copy (def: device size)\n"
-            "    dc          segment descriptor DC bit (default: 0)\n"
+            "    dc          xcopy segment descriptor DC bit (default: 0)\n"
             "    ibs         input block size (if given must be same as "
             "'bs=')\n"
             "    id_usage    sets list_id_usage field to hold (0), "
             "discard (2) or\n"
             "                disable (3)\n"
             "    if          file or device to read from (def: stdin)\n"
-            "    iflag       comma separated list from: [cat,dc,excl,"
-            "flock,null]\n"
+            "    iflag       comma separated list of flags applying to "
+            "IFILE\n"
             "    list_id     sets list_id field to ID (default: 1 or 0)\n"
             "    obs         output block size (if given must be same as "
             "'bs=')\n"
             "    of          file or device to write to (def: stdout), "
             "OFILE of '.'\n");
     pr2serr("                treated as /dev/null\n"
-            "    oflag       comma separated list from: [append,cat,pad,dc,"
-            "excl,flock,\n"
-            "                null]\n"
-            "    prio        set priority field to PRIO (def: 1)\n"
+            "    oflag       comma separated list of flags applying to "
+            "OFILE\n"
+            "    prio        set xcopy priority field to PRIO (def: 1)\n"
             "    seek        block position to start writing to OFILE\n"
             "    skip        block position to start reading from IFILE\n"
             "    time        0->no timing(def), 1->time plus calculate "
@@ -538,14 +531,31 @@
             "    verbose     0->quiet(def), 1->some noise, 2->more noise, "
             "etc\n"
             "    --help      print out this usage message then exit\n"
-            "    --on_dst    send XCOPY command to the output file/device\n"
-            "    --on_src    send XCOPY command to the input file/device.\n"
-            "                Default if this and --on_dst options not "
-            "given\n"
+            "    --on_dst    send XCOPY command to OFILE\n"
+            "    --on_src    send XCOPY command to IFILE\n"
             "    --verbose   same action as verbose=1\n"
             "    --version   print version information then exit\n\n"
             "Copy from IFILE to OFILE, similar to dd command; "
-            "but using the SCSI\nEXTENDED COPY (XCOPY) command.\n");
+            "but using the SCSI\nEXTENDED COPY (XCOPY) command. For list "
+            "of flags, use '-hh'.\n");
+    return;
+
+secondary_help:
+    pr2serr("FLAGS:\n"
+            "  append (o)     ignored\n"
+            "  excl           open corresponding device with O_EXCL\n"
+            "  flock          call flock(LOCK_EX|LOCK_NB)\n"
+            "  null           does nothing, placeholder\n"
+            "  pad            set xcopy data descriptor PAD bit on\n"
+            "                 corresponding device\n"
+            "  xcopy          send XCOPY command to corresponding device\n"
+            "\n"
+            "ENVIRONMENT VARIABLES:\n"
+            "  XCOPY_TO_DST   send XCOPY command to OFILE (destination) "
+            "if no other\n"
+            "                 indication\n"
+            "  XCOPY_TO_SRC   send XCOPY command to IFILE (source)\n"
+           );
 }
 
 static int
@@ -1319,7 +1329,7 @@
         else if (0 == strcmp(cp, "pad"))
             fp->pad = 1;
         else if (0 == strcmp(cp, "xcopy"))
-            ;   /* ignore, for ddpt compatibility */
+            ++fp->xcopy_given;   /* for ddpt compatibility */
         else {
             pr2serr("unrecognised flag: %s\n", cp);
             return 1;
@@ -1443,6 +1453,7 @@
     char * key;
     char * buf;
     int blocks = 0;
+    int num_help = 0;
     int num_xcopy = 0;
     int res, k;
     int infd, outfd, xcopy_fd;
@@ -1563,15 +1574,6 @@
                 pr2serr(ME "bad argument to 'oflag='\n");
                 return SG_LIB_SYNTAX_ERROR;
             }
-#if 0
-        } else if (0 == strcmp(key, "retries")) {
-            ixcf.retries = sg_get_num(buf);
-            oxcf.retries = ixcf.retries;
-            if (-1 == ixcf.retries) {
-                pr2serr(ME "bad argument to 'retries='\n");
-                return SG_LIB_SYNTAX_ERROR;
-            }
-#endif
         } else if (0 == strcmp(key, "seek")) {
             seek = sg_get_llnum(buf);
             if (-1LL == seek) {
@@ -1592,13 +1594,16 @@
             on_src = 1;
         else if (0 == strncmp(key, "--on_dst", 8))
             on_dst = 1;
+        else if (0 == strncmp(key, "-hhh", 4))
+            num_help += 3;
+        else if (0 == strncmp(key, "-hh", 3))
+            num_help += 2;
         else if ((0 == strncmp(key, "--help", 7)) ||
                  (0 == strncmp(key, "-h", 2)) ||
-                   (0 == strcmp(key, "-?"))) {
-            usage();
-            return 0;
-        } else if ((0 == strncmp(key, "--vers", 6)) ||
-                   (0 == strcmp(key, "-V"))) {
+                 (0 == strcmp(key, "-?")))
+            ++num_help;
+        else if ((0 == strncmp(key, "--vers", 6)) ||
+                 (0 == strcmp(key, "-V"))) {
             pr2serr(ME "%s\n", version_str);
             return 0;
         } else if (0 == strncmp(key, "--verb", 6))
@@ -1617,18 +1622,50 @@
             ;   /* ignore; for compatibility with ddpt */
         else {
             pr2serr("Unrecognized option '%s'\n", key);
-            pr2serr("For more information use '--help'\n");
+            if (num_help)
+                usage(num_help);
+            else
+                pr2serr("For more information use '--help'\n");
             return SG_LIB_SYNTAX_ERROR;
         }
     }
+    if (num_help) {
+        usage(num_help);
+        return 0;
+    }
     if (on_src && on_dst) {
         pr2serr("Syntax error - either specify --on_src OR "
                 "--on_dst\n");
         pr2serr("For more information use '--help'\n");
         return SG_LIB_SYNTAX_ERROR;
     }
-    if (!on_src && !on_dst)
-        on_src = 1;
+    if ((! on_src) && (! on_dst)) {
+        if ((!! ixcf.xcopy_given) == (!! oxcf.xcopy_given)) {
+            char * csp;
+            char * cdp;
+
+            csp = getenv(XCOPY_TO_SRC);
+            cdp = getenv(XCOPY_TO_DST);
+            if ((!! csp) == (!! cdp)) {
+#if DEF_XCOPY_SRC0_DST1 == 0
+                on_src = 1;
+#else
+                on_dst = 1;
+#endif
+            } else if (csp)
+                on_src = 1;
+            else
+                on_dst = 1;
+        } else if (ixcf.xcopy_given)
+            on_src = 1;
+        else
+            on_dst = 1;
+    }
+    if (verbose > 1)
+        pr2serr("Extended Copy(LID1) command will be sent to %s device "
+                "[%s]\n", (on_src ? "src" : "dst"),
+                (on_src ? ixcf.fname : oxcf.fname));
+
     if ((ibs && blk_sz && (ibs != blk_sz)) ||
         (obs && blk_sz && (obs != blk_sz))) {
         pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
@@ -1666,9 +1703,8 @@
     }
 
     if (verbose > 1)
-        pr2serr(ME "%s if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%"
-                PRId64 "\n", (on_src)?"on-source":"on-destination",
-                ixcf.fname, skip, oxcf.fname, seek, dd_count);
+        pr2serr(ME " if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%"
+                PRId64 "\n", ixcf.fname, skip, oxcf.fname, seek, dd_count);
     install_handler(SIGINT, interrupt_handler);
     install_handler(SIGQUIT, interrupt_handler);
     install_handler(SIGPIPE, interrupt_handler);