| >
> 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
|