(LOGO.JPG) Python for OpenVMS

(go to: table of contents, index, prev: Python in the OpenVMS environment, next: configuration guidelines)

This section gives some guidelines how to use the programming interface to OpenVMS routines.


file I/O

You should also take a look at the RMS section below.

record lengths

The DEC C RTL (or at least some versions) set the LRL (longest record length) field of a file to the maximum value (32767). This can cause problems with other applications (e.g. SORT).

There a two possibilities to attack the problem from the Python side:

  • via DEC C RTL
    Recent ECOs allow the programmer to set the logical name "DECC$DEFAULT_LRL".
    >>> fo = open ('TEST1.TMP', 'w')
    >>> fo.write ('data')
    >>> fo.close()
    
    $ write SYS$OUTPUT F$FILE_ATTRIBUTES ("TEST1.TMP", "LRL")
    32767
    $
    
    $ define DECC$DEFAULT_LRL 49
    
    >>> fo = open ('TEST2.TMP', 'w')
    >>> fo.write ('data')
    >>> fo.close()
    
    $ write SYS$OUTPUT F$FILE_ATTRIBUTES ("TEST2.TMP", "LRL")
    49
    $
    $ deassign DECC$DEFAULT_LRL
    Note that this affects ALL files created through the DEC C RTL.

  • use a special interface to the DEC C RTL open() routine and pass an RMS option. Note that this returns a file descriptor number, not a file object!

    Beginning with version 1.5.2-V007 there is also pyvms.file_open() available, which does return a file object.

    >>> import os, pyvms
    >>>
    >>> # O_TRUNC requests a NEW version of the file to be created !
    >>> flags = os.O_CREAT + os.O_TRUNC + os.O_WRONLY
    >>>
    >>> fd = pyvms.crtl_open ('TEST3.TMP', flags, 0777, ('mrs=53',))
    >>>
    >>> import posix
    >>> posix.write (fd, 'data')
    >>> posix.close (fd)
    
    $ write SYS$OUTPUT F$FILE_ATTRIBUTES ("TEST3.TMP", "LRL")
    53
    $

functions

arguments

Some functions (e. g.: vms_lib.currency) do not have any arguments. If you provide any, then the programming interface WILL raise a Python exception. The redundant argument is not silently ignored!

Some arguments of a function might not be required in a specific situation. As keyword arguments are not implemented you have to use 'None' as a placeholder instead - internally this will be changed to '0 passed by value'. See the examples of vms_lib.day() or vms_lib.getdvi() to get an idea.

OpenVMS system services usually require ALL arguments be specified. The Python interface routines usually substitute 'None' with '0 passed by value' to indicate an omitted argument. They also allow trailing 'unused' arguments to be omitted.

keyword arguments

e.g.: >>> ret = routine (p1 = val1)
are not supported for OpenVMS interface routines.

functions returning no data

Some routines do not need to return any 'data' - e.g. vms_lib.attach() returns 'None' upon successful completion. If an error happens, they will still raise a Python exception.

functions returning dictionaries

Some routines like 'vms_sys.getjpiw()' need to return a variable amount of data depending on its input parameters (the item list in this case). The data is stored under different 'keys' in a dictionary.

Using a tuple or a list would raise the question of which data is stored at which position.

The examples usually use 'dict' as the name for the reference to the object, but this is of course no requirement.


OpenVMS condition values

Using the native interfaces a programmer should _always_ check the returned condition value. Some routines also use the OpenVMS condition mechanism to signal errors, but a programmer should not rely on it.

Almost all routines within Python do not return the 'status' code from the underlying OpenVMS service. They use the Python model of raising a Python exception when an error happens.

There are some routines which behave differently - e.g. vms_lib.set_logical(). The reason for this is a uniform style of returning data - in this case it is a dictionary. Routines with different status values that can indicate success do not raise an exception, too.

The vms_sys.getmsg() routine allows the translation of the code into its text message:

    >>> import vms_sys
    >>> print vms_sys.getmsg (0x2c)
    ('%SYSTEM-F-ABORT, abort', (0, 0, 0, 0))
    >>>
    >>> print vms_sys.getmsg (0x2c) [0]
    %SYSTEM-F-ABORT, abort
    >>>

Sometimes, the condition value is in an IOSB (I/O status block) for which the 'vmsobj_iosb' object provides storage. See the examples section of vms_sys.getjpiw()


special OpenVMS datatypes

On OpenVMS, Python does not have a builtin 64-bit or 128-bit datatype.

64-bit quadword

These are simulated by using Python's "long integer" datatype. See vms_sys.gettim() or vms_sys.asctim() for examples. An exception are quadwords that are used for rightslist identifiers - see the explanation more below this text.

Using a "long integer" does allow the programmer to do calculations within Python. See the next section.

Date and time values are returned as a signed long integer, however bitmasks like privileges are returned as a positive long integer.

date and time calculations

An OpenVMS binary date + time is internally represented by a signed quadword. A positive value (including 0) indicates an absolute date + time (e.g. 29-FEB-2000 12:34:45.78). A negative value means a delta time (12 21:56:34.91), meaning 12 days, twenty-one hours, fifty-six minutes, thirty-four seconds and 91 hundredth of a second.

Although an OpenVMS 'delta time' is represented by a negative value it does not have a "direction". If you see something like "+01:00:00" - this is a 'combination time' - it means "add one hour to the current date + time".

Let's do some examples:

    >>> import vms_lib, vms_sys
If you are like me and always forget VMS' base date:
    >>> vms_sys.asctim (0L)
    '17-NOV-1858 00:00:00.00'
    >>>
The smallest increment is 100 nanoseconds. It's easy to find out how many of these 'ticks' are in a second:
    >>> vms_sys.bintim ('17-NOV-1858 00:00:01.00')
    10000000L
    >>>
Warning! The trailing 'L' shows that this is a Python 'long integer'. This is not a delta-time! '10000000L' really indicates the 17th of November in the year 1858, one second after midnight.

Now, a one-second delta time:

    >>> vms_sys.bintim ('0 00:00:01.00')
    -10000000L
    >>>

Let's use a different date:

    >>> feb29_y2k = vms_sys.bintim ('29-FEB-2000 12:34:56.78')
    >>> feb29_y2k
    44585444967800000L
    >>>

Calculate one second.

    >>> one_second = vms_sys.bintim ('0 00:00:01.00')
    >>> one_second
    -10000000L
    >>>

To add one second, we have to subtract the delta-time:

    >>> new_time = feb29_y2k - one_second
    >>> new_time
    44585444977800000L
    >>> vms_sys.asctim (new_time)
    '29-FEB-2000 12:34:57.78'
                        *
    >>> print new_time - feb29_y2k
    10000000L
    >>>

Remember: this value does NOT represent a one-second 'delta-time'!

There are also OpenVMS RTL routines to do date + time calculations:

    >>> new_time_2 = vms_lib.add_times (feb29_y2k, one_second)
    >>> new_time_2
    44585444977800000L
    >>> vms_sys.asctim (new_time_2)
    '29-FEB-2000 12:34:57.78'
                        *
    >>>

This routine, however, has some restrictions. Please see 'REFMAN Modules, vms_lib module, vms_lib.add_times' for details.

To subtract a delta time from an absolute date + time using Python's long integer datatype you have to ADD both values. There is also an OpenVMS RTL routine for this - see 'REFMAN Modules, vms_lib module, vms_lib.sub_times()'.

128-bit octaword

These are simulated by using Python's "long integer" datatype. See vms_sys.getutc() or vms_sys.ascutc() for examples.

Using a "long integer" does allow the programmer to do calculations within Python.


processes

privileges

A Python executable is not meant to be installed (via $INSTALL) with any privileges on OpenVMS! It is possible to turn off these elevated privileges by a call to vms_sys.setprv(), but a user can always just '$RUN' the Python executable...
The user can also enable additional privileges from his authorized privilege mask or turn on any privilege if he has the SETPRV privilege by calling vms_sys.setprv().

---

Privilege bitmask values are stored in module 'vms_prvdef'. @@ Ignore the 'PRV$_NULL' item code in this module. It is a work-around to a deficy in the VMSDEF2MAR.COM procedure which currently cannot cope with a VMSDEF module that has no item codes.

A privilege bitmask is 64 bits wide. All bit definitions in 'vms_prvdef' are defined as Python long integers.

>>> import vms_prvdef
>>>
>>> # a bit in the first longword
>>> vms_prvdef.PRV_M_ALLSPOOL
16L
>>> type (vms_prvdef.PRV_M_ALLSPOOL)
<type 'long int'>
>>>
>>> # a bit in the second longword
>>> hex (vms_prvdef.PRV_M_READALL)
'0x800000000L'
>>> type (vms_prvdef.PRV_M_READALL)
<type 'long int'>
>>>

Since 14-FEB-1999 it is no longer necessary to convert the bitmasks from a Python integer (32-bit) to a Python long integer (64-bit) because a BITMASK64 structure has been implemented. The following bits are still defined in the 'vms_prvdef' module with their (32-bit) values in the second longword:

PRV_M2_UPGRADE, PRV_M2_DOWNGRADE, PRV_M2_GRPPRV, PRV_M2_READALL, PRV_M2_IMPORT, PRV_M2_AUDIT, PRV_M2_SECURITY.
(_M2_ indicates that this bit is located in the 2nd longword.)

'vms_prvdef' also includes the bits with the '_M_' code and their real 64-bit value. See the example of PRV_M_READALL above.

Privileges are used, for example, in the following routines:

process identification (PID)

OpenVMS DCL utilities use an 8-character hex number as input and output for the PID and translate it internally because system services and run-time library routines use a binary longword.

Within Python a PID must always be specified as an integer data type - it is never a hex-string. e.g.:

$ PID = F$GETJPI(0,"PID")
$ show symbol PID
PID = "0000021A"
$ NUMBER = %X'PID'
$ show symbol NUMBER
NUMBER = 538 Hex = 0000021A Octal = 00000001032
$

You can use one of the following number representations within Python:

  • 538 - decimal
  • 01032 - octal - note the leading zero
  • 0x21a - hex - note the leading '0x'
>>> ctx,data = vms_lib.getjpi("JPI$_IMAGNAME",538)
>>> print data
DKA100:[PYTHON.PYTHON-1_5_1.VMS]PYTHON_ALPHA.EXE;1
>>>

('ctx' is either the process' PID or, during wildcard lookups, a context value. Please see the description of vms_lib.getjpi() for details.)

Several system services (vms_sys.delprc(), vms_sys.forcex(), ...) return the target process' PID if you specifiy 0 for the PID argument and a process name.

For consistency the Python interface always returns the target process' PID - no matter if you specify an explicit PID or use the process name argument.

---

Almost all examples in this documentation use a 'low' value for the PID. This is because development happens on non-clustered OpenVMS systems.


RMS

Many parts of the interfaces to the 'Record Management Services' (RMS) are not very thoroughly or even not at all (e.g. tape handling) tested.

You do need a good understanding of RMS and you need access to the 'OpenVMS Record Management Services Reference Manual' to make use of the interfaces - testers are always welcome.

RMS control blocks are accessible through so-called 'VMS objects'. The 'Python for OpenVMS Reference Manual' contains a list of these 'VMS objects'.

There are also some minimal example scripts in the 'demoes manual'.


security related objects

ACL + ACE

An ACL (Access Control List) is made up from one or more ACEs (Access Control list Entries). They are stored inside normal Python strings.

Warning!
ACEs are a set of bytes, not a set of printable characters. You should not output a binary ACE/ACL to a terminal, because the data stream can contain control sequences that alter the terminal's settings. Using the 'repr()' builtin is safe:

    >>> print repr (acestr)
    '\014\001\000\000\020\000\000\000\004\000\003\000'
    >>>

The vms_sys.format_acl() routine accepts a binary ACE and translates it in its ASCII equivalent. The vms_sys.parse_acl() routine accepts an ASCII string and translates it to the binary representation that is used inside OpenVMS.

The vms_sys.get_security() routine and the 'vmsobj_xabpro' object can be used to retrieve ACLs or ACEs from files and other objects (not via XABPRO).

rightslist identifiers

Identifiers (UIC and general) and their attributes are represented by Python integers (32-bit values). The 'vms_kgbdef' module contains the attribute bitmask values (KGB_M_name). Translation to / from the names can be done using the vms_sys.asctoid() and vms_sys.idtoasc() routines.

Some system services like vms_sys.add_holder() require a quadword containing the identifier in one of the longwords. The other usually is used for the attributes. In this case the interface routines do not use a single Python long integer but a tuple of 2 integers.


(go to: table of contents, index, prev: Python in the OpenVMS environment, next: configuration guidelines)

27-FEB-2000 ZE.