Using the __amrc structure

__amrc is a structure defined in stdio.h (when the compile-time option LANGLVL(EXTENDED) or LANGLVL(LIBEXT) is in effect) to help you determine errors resulting from an I/O operation. This structure is changed during system I/O and some C specific error situations. When looking at __amrc, be sure to copy the structure into a temporary structure of __amrctype since any I/O function calls will change the value of __amrc. Figure 1 shows the __amrc structure as it appears in stdio.h.

Note: __amrc is not used to record I/O errors in UNIX file system files.
Figure 1. __amrc structure
#if __TARGET_LIB__ >= __EDC_LE
  typedef struct __amrctype {
#else
  typedef struct {
#endif
                        /* The error or warning value from
                         * an I/O operation is in __error,
                         * __abend, __feedback or __alloc.
                         * Look at the value in __last_op
                         * to determine how to interpret
                         * the __code union.             */
    union {       1 
           int __error; /* error from OPEN/CLOSE,   2 
                         * GENCB/MODCB/TESTCB/SHOWCB  */
    struct {            /* abend code when errno set to EABEND   */
       unsigned short __syscode,      /* system abend code      */
                      __rc;           /* return code            */
    } __abend;    3 
      struct {
         unsigned char __fdbk_fill,
                       __rc,    /* reg 15 */
                       __ftncd, /* function code */
                       __fdbk;  /* feedback code */
      } __feedback;    4 
      struct {
         unsigned short __svc99_info,
                        __svc99_error;
      } __alloc;      5 
   } __code;
   unsigned int  __RBA;    6 
                          /* RBA value returned by VSAM after  *
                          * an ESDS or KSDS record is written *
                          * out; for RRDS it is a calculated  *
                          * value from the record number.     *
                          * It may be used in a subsequent    *
                          * call to flocate.                  */
   unsigned int      __last_op;  7 
                               /* #defined below */
   struct {
    unsigned int   __len_fill; /* __len + 4                   */
    unsigned int   __len;      /* length of msg in __str      */
    char           __str[120]; /* the actual data             */
    unsigned int   __parmr0;   /* parameter save area (R0)    */
    unsigned int   __parmr1;   /* parameter save area (R1)    */
    unsigned int   __fill2[2]; /* non-printable bytes         */
    char           __str2[64]; /* the actual data             */

   } __msg;        8 
                              /* error message               */

 #if __EDC_TARGET >= 0x22080000
   unsigned char        __rplfdbwd[4];   9  /*  rpl feedback word */
 #endif                       /*  __EDC_TARGET >= 0x22080000  */
 #if __EDC_TARGET >= 0x41080000    
 #ifdef  __LP64                 10 
   unsigned long        __XRBA; /* 8 byte RBA                 */
 #elif defined(__LL)
   unsigned long long   __XRBA; /* 8 byte RBA                 */
 #else
   unsigned int         __XRBA1;/* high half of 8 byte RBA    */
   unsigned int         __XRBA2;/* low half of 8 byte RBA     */
 #endif
                               /* QSAM to BSAM switch reason  */
   unsigned char        __amrc_noseek_to_seek;    11 
                            /* padding to make amrc 256 bytes */
   char                 __amrc_pad[23];
 #endif

} __amrc_type;
 1  union { ... } __code
The error or warning value from an I/O operation is in either __error, __abend, __feedback, or __alloc. You must look at __last_op to determine how to interpret the __code union.
 2  __error
__error contains the return code from the system macro or utility. Refer to Table 1 for further information.
 3  __abend
This struct contains the abend code when errno is set to indicate a recoverable I/O abend. __syscode is the system abend code and __rc is the return code. For more information on the abend codes, see the System Codes manual as listed in z/OS Information Roadmap. The macros __abendcode() and __rsncode() may be set to the abend code and reason code of a TSO CLIST or command when invoked with system().
 4  __feedback
This struct is used for VSAM only. The __rc stores the VSAM register 15, __fdbk stores the VSAM error code or reason code, and __RBA stores the RBA after some operations.
 5  __alloc
This struct contains errors during fopen() or freopen() calls when defining files to the system using SVC 99. See the Systems Macros manual, as listed in z/OS Information Roadmap, for more information on these fields as set by SVC 99.
 6  __RBA
This is the RBA value returned by VSAM after an ESDS or KSDS record is written out. For a RRDS, it is the calculated value from the record number. It may be used in subsequent calls to flocate(). The __amrc.__RBA field is defined as an unsigned int, and therefore will only contain a 4-byte RBA value. This field will be set to -1 when the RBA is beyond 4GB in an extended addressable VSAM data set. In this case, the __XRBA field should be used.
 7  __last_op
Contains a value that indicates the last I/O operation being performed by z/OS® XL C/C++ at the time the error occurred. These values are shown in Table 1.
 8  __msg
This may contain the system error messages from read or write operations emitted from the BSAM SYNADAF macro instruction. This field will not always be filled. If you print this field using the %s format, you should print the string starting at the sixth position because of possible null characters found in the first 6 characters. Special messages for PDSEs are contained in the positions 136 through 184. See the Data Administration manual as listed in z/OS Information Roadmap for more information. This field is used by the SIGIOERR handler.
 9  __rplfdbwd
Contains feedback information related to a VSAM RLS failure. This is the feedback code from the IFGRPL control block.
 10  __XRBA
This is the 8 byte relative byte address returned by VSAM after an ESDS or KSDS record is written out. For an RRDS, it is the calculated value from the record number. It may be used in subsequent calls to flocate().
 11  __amrc_noseek_to_seek
Contains the reason for the switch from QSAM (noseek) to BSAM with NOTE and POINT macros requested (seek) by the XL C/C++ Runtime Library. This field is set when system-level I/O macro processing triggers an ABEND condition. The macro name values (defined in stdio.h) for this field are as follows:
Macro Definition
__AM_BSAM_NOSWITCH No switch was made.
__AM_BSAM_UPDATE Data set is open for update
__AM_BSAM_BSAMWRITE Data set is already open for write (or update) in the same C process
__AM_BSAM_FBS_APPEND Data set is recfm=FBS and open for append
__AM_BSAM_LRECLX Data set is recfm=LRECLX (used for VBS data sets where records span the largest blocksize allowed on the device)
__AM_BSAM_PARTITIONED_DIRECTORY Data set is the directory for a regular or extended partitioned data set
__AM_BSAM_PARTITIONED_INDIRECT Data set is a member of a partitioned data set, and the member name was not specified at allocation

Sample program CCNGDI1 (Figure 2) demonstrates how to print the __amrc structure after an error has occurred to get information that may help you to diagnose an I/O error. The program writes to a file until it is full. When the file is full, the program fails. Following the I/O failure, the program makes a copy of the __amrc structure, and prints the number of successful writes to the file, the errno, the __last_op code, the abend system code and the return code.

Figure 2. Example of printing the __amrc structure
/* this example demonstrates how to print the __amrc structure */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
   FILE *fp;
   __amrc_type save_amrc;
   char buffer[80];
   int i = 0;

   /* open an MVS binary file */

   fp = fopen("testfull.file","wb, recfm=F, lrecl=80");
   if (fp == NULL) exit(99);

   memset(buffer, 'A', 80);

   /* write to MVS file until it runs out of extents */

   while (fwrite(buffer, 1, 80, fp) == 80)
      ++i;

   save_amrc = *__amrc;  /* need copy of __amrc structure */

   printf("number of successful fwrites of 80 bytes = %d\n", i);
   printf("last fwrite errno=%d lastop=%d syscode=%X rc=%d\n",
           errno,
           save_amrc.__last_op,
           save_amrc.__code.__abend.__syscode,
           save_amrc.__code.__abend.__rc);

   return 0;
}