|  | > 
> Since reading your response, I've been playing with perror on a V6.1 and a V7.1
> system. I'm still working to find an error that would reproduce an RMS$_ACC
> error, but in the mean time, I've seen that on OpenVMS VAX V7.1 you're
> translating RMS$_CRE/SS$_BADIRECTORY into "i/o error". That's not the problem my
> customer is having, but it's not a very good translation, either.
> 
  I managed to cause RMS$_ACC error status specifying unknown node in the file
  specification for fopen() function - see example below.
  You cannot expect, that perror() will map every VMS condition value to a
  separate errno value with its own message explaining the error. I have no
  idea how many condition values exist on VMS (I think, only <ssdef.h> contains
  more than 400 condition values) but the total number of errno values, as can
  be seen from the <errno.h> header, is only 86:
#ifndef __HIDE_FORBIDDEN_NAMES
#define __ERRNO_MAX     86     /* MUST equal largest errno value        */
#define EVMSERR         65535  /* error for non-translatable VMS errors */
#endif
  Due to its ambiguity, the perror() function is not the best way to analyze
  a VMS condition value. For example, the following VMS status codes are mapped
  to the same EIO errno having the "i/o error" message:
    RMS$_IFI,		EIO,
    RMS$_ISI,		EIO,	
    RMS$_CRE,		EIO,		
    RMS$_ACC,		EIO,
    RMS$_DAC,		EIO,
    RMS$_ENT,		EIO,
    RMS$_EXT,		EIO,
    RMS$_FND,		EIO,
    RMS$_MKD,		EIO,
    RMS$_DPE,		EIO,
    RMS$_SPL,		EIO,
    RMS$_RUF,		EIO,
    RMS$_WRTJNL_AIJ,	EIO,
    RMS$_WRTJNL_BIJ,	EIO,
    RMS$_WRTJNL_ATJ,	EIO,
    RMS$_WRTJNL_RUJ,	EIO,
    RMS$_RRF,		EIO,
    RMS$_DDTM_ERR,	EIO,
    RMS$_ATR,		EIO,
    RMS$_ATW,		EIO,
    RMS$_CCF,		EIO,
    RMS$_CDA,		EIO,
    RMS$_CHN,		EIO,
    RMS$_RER,		EIO,
    RMS$_RMV,		EIO,
    RMS$_RPL,		EIO,
    RMS$_SYS,		EIO,
    RMS$_WER,		EIO,
    RMS$_WPL,		EIO,
    RMS$_IFA,		EIO,
    RMS$_WBE,		EIO,
    RMS$_ENQ,		EIO,
    RMS$_NETFAIL,	EIO,
    RMS$_SUPPORT,	EIO,
    RMS$_CRMP,		EIO,
    RMS$_DTFCFGFIL,	EIO,
    RMS$_REENT,		EIO,
    RMS$_ACC_RUJ,	EIO,
    RMS$_TMR,		EIO,
    RMS$_ACC_AIJ,	EIO,
    RMS$_ACC_BIJ,	EIO,
    RMS$_ACC_ATJ,	EIO,
    RMS$_DTFREGFIL,	EIO,
    RMS$_JNLNOTAUTH,	EIO,		
  All possible errno values and their associated messages can be found in
  Table 4-2 in the DEC C RTL Reference Manual.
  So, regardless of the fix done to OpenVMS V7.1, perror() will always return
  an "i/o error" message for RMS$_ACC status.
  As stated in Section 4.1 in the Manual, the OpenVMS condition value is
  available in the vaxc$errno variable. The message associated with OpenVMS
  condition value can be obtained through strerror() function if errno argument
  is set to EVMSERR.
> 
> Do you have a list of the STV values for RMS$_ACC and the corresponding error
> text as of your fix? This customer is starting to bristle, and could use the
> reassurance that the log file will give the answer in the future.
  I don't have the list. The log file will give the answer only if strerror()
  will be used instead of perror() and the fix done for OpenVMS V7.1 will be
  ECOed for V6.2. Currently it is ECOed for V7.0 only.
  The fix done to OpenVMS V7.1 is that the vaxc$errno is set to the FAB$L_STV
  status. Prior to V7.1, the errno was set to EVMSERR and vaxc$errno was set
  to FAB$L_STS status. The example below illustrates the difference between the
  OpenVMS V6.2 and V7.1. As you can see from the example, on V7.1 one does not
  need the "err" callback function to get a real status - this status can be
  obtained via the call to strerror().
> 
> For the present, I learned that your fix will only help my test program - the
> actual code shipped with the product is built with VAX C :-(  I'll be asking for
> clues over in that conference next.
> 
  Even though the product is compiled using VAX C, and, I guess, is linked
  against VAX C RTL, probably, you can relink the product to use the DEC C
  RTL instead. This will let you take advantage of the new features of the DEC
  C RTL and bug fixes. See section 1.3 RTL Linking Options on VAX Systems in
  the Manual.
  Boris
$ cc/version/noobj _nl0:
DEC C V5.0-003 on OpenVMS Alpha V6.2-1H1
$ run x
acp file access failed
remote node is unknown
fopen: non-translatable vms error code: 0x1C002
%rms-e-acc, acp file access failed
acp file access failed
$ cc/version/noobj _nl0:
DEC C V5.2-003 on OpenVMS Alpha V7.1
$ run x
acp file access failed
remote node is unknown
fopen: i/o error
remote node is unknown
X.C
===
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <rms.h>
static int err_callback(int *tmp, struct FAB *fab, struct RAB *rab)
{
  puts(strerror(EVMSERR,fab->fab$l_sts));
  puts(strerror(EVMSERR,fab->fab$l_stv));
  return -1;
}
main()
{
  int i;
  if ( !fopen("abcdef::mba1:", "r", "err", err_callback, &i) ) {
    perror("fopen");
    puts(strerror(EVMSERR));
  }
}
 | 
|  |     Boris, you said:
      
    "You cannot expect, that perror() will map every VMS condition value to a
    separate errno value with its own message explaining the error."
    
    I have no expectation that perror will do this. What I expected is that,
    for every VMS error condition which is reasonably mapped to an errno
    value, that the mapping is performed. I did not previously consider it
    reasonable to map RMS$_ACC to "i/o error", but I'm willing to concede
    that others might argue that this is reasonable.
    
    Users of OpenVMS expect better diagnostics than "i/o error". The
    previous functionality at least used to output "%RMS-E-ACC", so that we
    used to have some kind of idea of what was going on, without having to
    use radically-different code between OpenVMS, Digital UNIX, and Ultrix.
    I had hoped that future versions of the RTL would only improve upon
    this functionality by outputting both the STS and STV values.
    
    Now you tell me that we're back to the Least Common Denominator. I'm
    hearing that instead of extending perror to output the additional
    information OpenVMS can provide, the decision was made to lose
    information, in fact to hide it from the customer, the field, and
    Engineering. I think I'm hearing that in order to get the functionality
    we used to have, we have to modify all the open() calls in DECdns to
    include an "err" routine, then test and ship a new ECO!
    
    And to compile it with a new compiler besides!
    
    If I'm reading this wrong, please let me know. Right now, I'm not very
    pleased, and neither will the customer be.
    
    
    re: .4:
    
    If you are referring to the _fstat function, my readings in the VAXC
    conference suggest that it takes a file descriptor as its first
    argument. I need to get the error status in the case that an open
    fails. In that case, I have no file descriptor to pass to _fstat.
    
    
    Thanks,
    John Saunders
    DECdns Engineering
 | 
|  | John,
  First off, thank you for the problem report.  While our hands are tied
  in some respects, we may be able to work up a design to provide more
  information from both the strerror() and perror() routines.
  I don't have the ANSI specification in front of me, but it specifies
  exactly what the perror() routine is expected to do and how the string
  displayed by perror() relate to strerror().
     perror(s) == fprintf(stderr, "%s: %d", s, strerror(errno))
  In the DEC C RTL, we have both errno and vaxc$errno.  In fact, perror can
  be thought of as
     perror(s) == fprintf(stderr, "%s: %d", s, strerror(errno, vaxc$errno))
  The problem is that the value of vaxc$errno is defined only when errno
  is equivalent to EVMSERR.  The strerror() function will only examine the
  second argument if the first is EVMSERR.
  In the example of opening a file with an invalid node name, the RMS status
  is RMS$_ACC with a secondary status of SS$_NOSUCHNODE.  The DEC C RTL 
  converts RMS$_ACC into an errno value of EIO (I/O Error).  The value of
  vaxc$errno is set to SS$_NOSUCHNODE.
  Another ANSI rule that comes into play is that we can only touch errno
  if an error occurs during the specific call.  We are not permitted to 
  ever clear errno.  ANSI makes no such rules about vaxc$errno, since that
  is a DEC C extension.
  In order to make improvements in this area, I imagine that we will need 
  to change the current design to store
      errno        -- the c translation of the error
      vaxc$errno   -- the actual error which occured
      vaxc$errno2  -- the secondary status if vaxc$errno has one
  The value of vaxc$errno would be RMS$_ACC in this example while the value
  of vaxc$errno2 would be SYS$_NOSUCHNODE.  When an error occurs, errno is
  established.  The vaxc$errno and vaxc$errno2 would have to kept consistent
  with changes made to errno.  If errno was set to an error such as EINVAL
  (invalid argument), then both vaxc$errno and vaxc$errno2 would be cleared.
  If errno was set to a value based on a single error status, the vaxc$errno2
  would be cleared.  Only in the case of a system error which has secondary
  information would all three cells contain a value.
  My project will investigate what we can do to improve the usability of 
  perror and strerror while retaining upward compatibility for those 
  applications which rely on the values of vaxc$errno.  Based on our findings,
  these changes may or may not be ECOed onto a platform.  Have you ever 
  issued an ECO kit which broke products such as Oracle?  It's not a pleasant
  experience.
  Also, please do not assume that any changes will be done to the VAX C RTL 
  based on this note.  It would require at least a priority 1 or a high 2 
  IPMT case to have changes made to the VAXCRTL[G].EXE images.
Duane Smith
OpenVMS DEC C Runtime Library
 | 
|  | John,
  First off, thank you for the problem report.  While our hands are tied
  in some respects, we may be able to work up a design to provide more
  information from both the strerror() and perror() routines.
  I don't have the ANSI specification in front of me, but it specifies
  exactly what the perror() routine is expected to do and how the string
  displayed by perror() relate to strerror().
     perror(s) == fprintf(stderr, "%s: %s", s, strerror(errno))
  In the DEC C RTL, we have both errno and vaxc$errno.  In fact, perror can
  be thought of as
     perror(s) == fprintf(stderr, "%s: %s", s, strerror(errno, vaxc$errno))
  The problem is that the value of vaxc$errno is defined only when errno
  is equivalent to EVMSERR.  The strerror() function will only examine the
  second argument if the first is EVMSERR.
  In the example of opening a file with an invalid node name, the RMS status
  is RMS$_ACC with a secondary status of SS$_NOSUCHNODE.  The DEC C RTL 
  converts RMS$_ACC into an errno value of EIO (I/O Error).  The value of
  vaxc$errno is set to SS$_NOSUCHNODE.
  Another ANSI rule that comes into play is that we can only touch errno
  if an error occurs during the specific call.  We are not permitted to 
  ever clear errno.  ANSI makes no such rules about vaxc$errno, since that
  is a DEC C extension.
  In order to make improvements in this area, I imagine that we will need 
  to change the current design to store
      errno        -- the c translation of the error
      vaxc$errno   -- the actual error which occured
      vaxc$errno2  -- the secondary status if vaxc$errno has one
  The value of vaxc$errno would be RMS$_ACC in this example while the value
  of vaxc$errno2 would be SYS$_NOSUCHNODE.  When an error occurs, errno is
  established.  The vaxc$errno and vaxc$errno2 would have to kept consistent
  with changes made to errno.  If errno was set to an error such as EINVAL
  (invalid argument), then both vaxc$errno and vaxc$errno2 would be cleared.
  If errno was set to a value based on a single error status, the vaxc$errno2
  would be cleared.  Only in the case of a system error which has secondary
  information would all three cells contain a value.
  My project will investigate what we can do to improve the usability of 
  perror and strerror while retaining upward compatibility for those 
  applications which rely on the values of vaxc$errno.  Based on our findings,
  these changes may or may not be ECOed onto a platform.  Have you ever 
  issued an ECO kit which broke products such as Oracle?  It's not a pleasant
  experience.
  Also, please do not assume that any changes will be done to the VAX C RTL 
  based on this note.  It would require at least a priority 1 or a high 2 
  IPMT case to have changes made to the VAXCRTL[G].EXE images.
Duane Smith
OpenVMS DEC C Runtime Library
 | 
|  | Thanks for the responses. If I understand you, vaxc$errno is documented to be
defined only when errno is EVMSERR. If this is the case, then you do not have to
change vaxc$errno (and vaxc$errno2) whenever errno changes, but only when it is
set to EVMSERR. That is, the only code that should have to touch
vaxc$errno/errno2 is code which sets errno to EVMSERR.
If this is so, vaxc$errno2 should be defined to be set only when errno is
EVMSERR and vaxc$errno contains an RMS error. In that case, it would be defined
to be the FAB$L_STV or RAB$L_STV value, depending on which sort of operation
failed.
For consistancy then, strerror should be extended to have an optional third
argument, which is only examined when errno is EVMSERR and vaxc$errno is an RMS
error. The third argument would be the STV value. The pair of
vaxc$errno,vaxc$errno2 could then be supplied to the SYS$PUTMSG call that writes
the string returned by strerror (don't forget to grow that string!).
perror could then be equivalent to:
perror(s) == fprintf (stderr, "%s: %s", s,
			strerror (errno, vaxc$errno, vaxc$errno2));
This should be OK by ANSI and any test suite, at least for any ANSI-defined
errno values.
Of course, you should review the mappings of VMS errors to errno values: EIO was
a stretch for something to map to, and in this case caused valuable information
to be lost.
We don't expect any changes to ever be made to VAXCRTL, by the way. We'll
eventually be converting to DECC. My hope is that when we do, some ECO will have
been issued on the platforms we support that will allow us to get useful
information from the Field without having to recode all our opens and creat's.
Thanks,
John Saunders
DECdns Engineering
P.S. I prefer vaxc$rms_stv or something. It's not an "errno".
P.P.S. If we've got to recode, I'll probably try macros called "open" and
"creat" that call our own function, which will call the real open and creat with
the three additional parameters ["err", file_open_rtn, x]. file_open_rtn would
then have to store STS and STV. We'd then have to have our own perror and
strerror that would use the STS and STV. This would sure be cleaner if you did
it rather than I...
 | 
|  | >  I don't have the ANSI specification in front of me, but it specifies
>  exactly what the perror() routine is expected to do and how the string
>  displayed by perror() relate to strerror().
>
>     perror(s) == fprintf(stderr, "%s: %s", s, strerror(errno))
        My copy is handy. :-)  The wording translates more like
        
        	if ((s == NULL) || (*s == '\0'))
        	    fprintf(stderr, "%s\n", strerror(errno));
        	else
        	    fprintf(stderr, "%s: %s\n", s, strerror(errno));
        which doesn't change anything that was said afterward.
        I just like to peek at the standard. :-)
        
>  Another ANSI rule that comes into play is that we can only touch errno
>  if an error occurs during the specific call.  We are not permitted to 
>  ever clear errno.  ANSI makes no such rules about vaxc$errno, since that
>  is a DEC C extension.
        
        Unless it has changed from the X3.159-1989 document, the rule
        is
        
        	The value of errno is zero at program startup, but is
        	never set to zero by any library function.  The value
        	of errno may be set to nonzero by a library function
        	call whether or not there is an error, provided the
        	use of errno is not documented in the description of
        	the function in the standard.
        
        So for example the use of errno is not documented in the
        description of the fopen() function in the standard, so even
        successful fopen() calls can modify errno (although they
        cannot change a nonzero errno back to zero).
        
        As long as users only check errno after a failed call (for
        example, only check error if fopen returned a null pointer)
        they won't trip over this.
        
        On OpenVMS, the call fopen(filename, "w") checks if there is
        an existing version of `filename' so that it can inherit its
        attributes (record format, record attribute, etc.).  If there
        was no existing version, the result was setting errno to
        ENOENT, even though the fopen did successfully create the new
        file and returned a non-null pointer.  It is compliant to
        change errno to ENOENT on a successful fopen() call, but
        people complained anyway so we changed it to restore the old
        value of errno in this case.  To the standard...and beyond! :-)
        
        Dan
 |