To err(no) may be human...
I was reworking a part of a large project which incorporates multi-threading employing the POSIX threads API. When I went to test these code changes, the product failed but without any clear reason being given in an error message. Why no error message, one of the more prudent earmarks of the OpenVMS operating system? Because the POSIX API library on OpenVMS returns error codes which are significant to or meaningful when the underlying operating system is unix, unix based or Linux.I was able to correct the problem causing the program failure after I had checked and analyzed the value returned from the POSIX thread library call; however, this required manually looking up the code to decipher its meaning. This is not how I would prefer to handle this situation when a product, which will run on production systems, is released. So, I was determined to find a way to get these POSIX API calls to return with an error message that was meaningful and descriptive like the typical OpenVMS run-time library calls, system services and utilities.
The error codes returned by the POSIX library API are defined in the C language include file errno.h. These values, returned by the POSIX thread API, are representative of the unix operating system — replete with such meaningful error messages as
Not a typewriter
. As whimsically kludgy as these messages are, I'd welcome seeing even these messages when a failure occurs; however, these error numbers are simply an enumerated list of values and do not fit into the OpenVMS definition of an error return value. What was I to do?I'd thought about mapping each of the eighty odd messages into an OpenVMS message which would, essentially, maintain some similar meaning but I decided against it. I then thought, I certainly can not be the only programmer on OpenVMS who has been faced this same issue; there must be some OpenVMS or C RTL call which will translate these unix errno codes to an OpenVMS message value. So, I looked through the C RTL help for a routine which would map the unix error numbers to OpenVMS message values. Nothing, however, stood out as being available. I then took note of another, similar, include file: errnodef.h. This file defines a list of similarly enumerated unix message names with a C$_ prefix as external values. If that's the case, these represent some value that is resolved at
LINK
time.The most obvious place for these external values to be resolved was the C RTL shareable image DECC$SHR.EXE. Using the OpenVMS image analyzer, I took a look at the C RTL shareable image to see what these values were.
$ ANALYZE/IMAGE SYS$SHARE:DECC$SHR.EXE
:
:
1) Universal Symbol Specification (EGSD$C_SYMG)
data type: DSC$K_DTYPE_Z (0)
symbol flags:
(0) EGSY$V_WEAK 0
(1) EGSY$V_DEF 1
(2) EGSY$V_UNI 1
(3) EGSY$V_REL 0
(4) EGSY$V_COMM 0
(5) EGSY$V_VECEP 0
(6) EGSY$V_NORM 0
psect: 0
value: 0 (%X'00000000')
symbol vector entry (constant)
%X'00000000 00000000'
%X'00000000 0035800C' (3506188)
symbol: "C$_EPERM"
2) Universal Symbol Specification (EGSD$C_SYMG)
data type: DSC$K_DTYPE_Z (0)
symbol flags:
(0) EGSY$V_WEAK 0
(1) EGSY$V_DEF 1
(2) EGSY$V_UNI 1
(3) EGSY$V_REL 0
(4) EGSY$V_COMM 0
(5) EGSY$V_VECEP 0
(6) EGSY$V_NORM 0
psect: 0
value: 16 (%X'00000010')
symbol vector entry (constant)
%X'00000000 00000000'
%X'00000000 00358014' (3506196)
symbol: "C$_ENOENT"
3) Universal Symbol Specification (EGSD$C_SYMG)
data type: DSC$K_DTYPE_Z (0)
symbol flags:
(0) EGSY$V_WEAK 0
(1) EGSY$V_DEF 1
(2) EGSY$V_UNI 1
(3) EGSY$V_REL 0
(4) EGSY$V_COMM 0
(5) EGSY$V_VECEP 0
(6) EGSY$V_NORM 0
psect: 0
value: 32 (%X'00000020')
symbol vector entry (constant)
%X'00000000 00000000'
%X'00000000 0035801C' (3506204)
symbol: "C$_ESRCH"
4) Universal Symbol Specification (EGSD$C_SYMG)
data type: DSC$K_DTYPE_Z (0)
symbol flags:
(0) EGSY$V_WEAK 0
(1) EGSY$V_DEF 1
(2) EGSY$V_UNI 1
(3) EGSY$V_REL 0
(4) EGSY$V_COMM 0
(5) EGSY$V_VECEP 0
(6) EGSY$V_NORM 0
psect: 0
value: 48 (%X'00000030')
symbol vector entry (constant)
%X'00000000 00000000'
%X'00000000 00358024' (3506212)
symbol: "C$_EINTR"
5) Universal Symbol Specification (EGSD$C_SYMG)
data type: DSC$K_DTYPE_Z (0)
symbol flags:
(0) EGSY$V_WEAK 0
(1) EGSY$V_DEF 1
(2) EGSY$V_UNI 1
(3) EGSY$V_REL 0
(4) EGSY$V_COMM 0
(5) EGSY$V_VECEP 0
(6) EGSY$V_NORM 0
psect: 0
value: 64 (%X'00000040')
symbol vector entry (constant)
%X'00000000 00000000'
%X'00000000 0035802C' (3506220)
symbol: "C$_EIO"
:
:
These looked suspiciously like OpenVMS message values to me. A sixth sense, so to speak, that one acquires after working with OpenVMS for 30 years. However, there was only one way to be sure. I took one of the codes and entered:
$ EXIT %x0035800C
%C-F-NOMSG, Message number 0035800C
Promising! So, I now looked for a corresponding message file in SYS$MESSAGE: and found DECC$MSG.EXE. I repeated the previous test.
$ SET MESSAGE SYS$MESSAGE:DECC$MSG.EXE
$ EXIT %x0035800C
%C-F-EPERM, not owner
Presto! Nearly home.
At this point, I was now convinced it would be a fairly straightforward task to algorithmically map this 'unixy' returned error number to the corresponding OpenVMS message value. Each of the OpenVMS message values I found in DECC$SHR.EXE differed from the prior by eight or shifted to the left by three bits. The lower three bits of an OpenVMS message code represent the severity of the error:
- [000] -W- Warning
- [001] -S- Success
- [010] -E- Error
- [011] -I- Informational
- [100] -F- Fatal
#include <errno.h>
#include <ernodef.h>
#define DECC$ERRNO_TO_MSGCOD(x) ( C$_EPERM+((x-1)<<STS$V_CODE) )
After reporting these findings to comp.os.vms, Hartmut Becker pointed out that the C$_ values were not dense. In other words, some of the newer errno messages added in recent versions would not map properly due to the non-linearity of their assignment. This didn't really affect me nor my effectual goal rooted in returning a meaningful error from the POSIX thread APIs. The POSIX thread APIs would not return these newly added errno conditions. However, I was up to the challenge and modified my mapping macro's algorithm to address the non-dense nature of this relationship. The result of this is shown below.
#include <errno.h>
#include <ernodef.h>
#ifdef EABANDONED
#define DECC$ERRNO_TO_MSGCOD(x) (x <= EBADMSG ? \
C$_EPERM+((x-1)<<STS$V_CODE) \
: C$_EABANDONED+((x-1-EBADMSG)<<STS$V_CODE) )
#else
#define DECC$ERRNO_TO_MSGCOD(x) ( C$_EPERM+((x-1)<<STS$V_CODE) )
#endif
So, in conclusion, while to errno may be human, to be able to forge and return a meaningful OpenVMS error message is divine.