HP OpenVMS Systems Documentation

Content starts here

OpenVMS Programming Concepts Manual


Previous Contents Index

23.16.3 Record Terminators

A QIO read operation ends when the user enters a terminator or when the input buffer fills, whichever occurs first. The standard set of terminators applies unless you specify the 4 argument in the read QIO operation. You can examine the terminator that ended the read operation by examining the input buffer starting at the terminator offset (second word of the I/O status block). The length, in bytes, of the terminator is specified by the high-order word of the I/O status block. The third word of the I/O status block contains the value of the first character of the terminator.

Examining the terminator enables you to read escape sequences from the terminal, provided that you modify the QIO read operation with the IO$M_ESCAPE modifier (or the ESCAPE terminal characteristic is set). The first character of the terminator will be the ESC character (an ASCII value of 27). The remaining characters will contain the value of the escape sequence.

23.16.4 File Terminators

You must examine the terminator to detect end-of-file (Ctrl/Z) on the terminal. No error condition is generated at the QIO level. If the user presses Ctrl/Z, the terminator will be the SUB character (an ASCII value of 26).

23.17 Device Allocation

Many I/O devices are shareable; that is, more than one process at a time can access the device. By calling the Assign I/O Channel (SYS$ASSIGN) system service, a process is given a channel to the device for I/O operations.

In some cases, a process may need exclusive use of a device so that data is not affected by other processes. To reserve a device for exclusive use, you must allocate it.

Device allocation is normally accomplished with the DCL command ALLOCATE. A process can also allocate a device by calling the Allocate Device (SYS$ALLOC) system service. When a device has been allocated by a process, only the process that allocated the device and any subprocesses it creates can assign channels to the device.

When you call the SYS$ALLOC system service, you must provide a device name. The device name specified can be any of the following:

  • A physical device name, for example, the tape drive MTB3:
  • A logical name, for example, TAPE
  • A generic device name, for example, MT:

If you specify a physical device name, SYS$ALLOC attempts to allocate the specified device.

If you specify a logical name, SYS$ALLOC translates the logical name and attempts to allocate the physical device name equated to the logical name.

If you specify a generic device name (that is, if you specify a device type but do not specify a controller or unit number, or both), SYS$ALLOC attempts to allocate any device available of the specified type. For more information about the allocation of devices by generic names, see Section 23.15.

When you specify generic device names, you must provide fields for the SYS$ALLOC system service to return the name and the length of the physical device that is actually allocated so that you can provide this name as input to the SYS$ASSIGN system service.

The following example illustrates the allocation of a tape device specified by the logical name TAPE:



#include <descrip.h>
#include <lib$routines.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>

main() {
        unsigned int status;
        char devstr[64];
        unsigned short phylen, tapechan;

        $DESCRIPTOR(logdev,"TAPE");     /* Descriptor for logical name */
        $DESCRIPTOR(devdesc,devstr);    /* Descriptor for physical name */

/* Allocate a device */
        status = SYS$ALLOC( &logdev,    /* devnam - device name */      (1)
                            &phylen,    /* phylen - length device name string */
                            &devdesc,   /* phybuf - buffer for devnam string */
                            0, 0);
        if (!$VMS_STATUS_SUCCESS( status ))
                LIB$SIGNAL( status );

/* Assign a channel to the device */
        status = SYS$ASSIGN( &devdesc,          /* devnam - device name */  (2)
                             &tapechan,         /* chan - channel number */
                             0, 0, 0);
        if (!$VMS_STATUS_SUCCESS( status ))
                LIB$SIGNAL( status );

/* Deassign the channel */
        status = SYS$DASSGN( tapechan );        /* chan - channel number */(3)
        if (!$VMS_STATUS_SUCCESS( status ))
                LIB$SIGNAL( status );

/* Deallocate the device */
        status = SYS$DALLOC( &devdesc,          /* devnam - device name */
                             0 );               /* acmode - access mode */
        if (!$VMS_STATUS_SUCCESS( status ))
                LIB$SIGNAL( status );

}

  1. The SYS$ALLOC system service call requests allocation of a device corresponding to the logical name TAPE, defined by the character string descriptor LOGDEV. The argument DEVDESC refers to the buffer provided to receive the physical device name of the device that is allocated and the length of the name string. The SYS$ALLOC service translates the logical name TAPE and returns the equivalence name string of the device actually allocated into the buffer at DEVDESC. It writes the length of the string in the first word of DEVDESC.
  2. The SYS$ASSIGN command uses the character string returned by the SYS$ALLOC system service as the input device name argument, and requests that the channel number be written into TAPECHAN.
  3. When I/O operations are completed, the SYS$DASSGN system service deassigns the channel, and the SYS$DALLOC system service deallocates the device. The channel must be deassigned before the device can be deallocated.

23.17.1 Implicit Allocation

Devices that cannot be shared by more than one process (for example, terminals and line printers) do not have to be explicitly allocated. Because they are nonshareable, they are implicitly allocated by the SYS$ASSIGN system service when SYS$ASSIGN is called to assign a channel to the device.

23.17.2 Deallocation

When the program has finished using an allocated device, it should release the device with the Deallocate Device (SYS$DALLOC) system service to make it available for other processes.

At image exit, the system automatically deallocates devices allocated by the image.

23.18 Mounting, Dismounting, and Initializing Volumes

This section introduces you to using system services to mount, dismount, and initialize disk and tape volumes.

23.18.1 Mounting a Volume

Mounting a volume establishes a link between a volume, a device, and a process. A volume, or volume set, must be mounted before I/O operations can be performed on the volume. You interactively mount or dismount a volume from the DCL command stream with the MOUNT or DISMOUNT command. A process can also mount or dismount a volume or volume set programmatically using the Mount Volume (SYS$MOUNT) or the Dismount Volume (SYS$DISMOU) system service, respectively.

Mounting a volume involves two operations:

  1. Place the volume on the device and start the device (by pressing the START or LOAD button).
  2. Mount the volume with the SYS$MOUNT system service.

23.18.1.1 Calling the SYS$MOUNT System Service

The Mount Volume (SYS$MOUNT) system service allows a process to mount a single volume or a volume set. When you call the SYS$MOUNT system service, you must specify a device name.

The SYS$MOUNT system service has a single argument, which is the address of a list of item descriptors. The list is terminated by a longword of binary zeros. Figure 23-8 shows the format of an item descriptor.

Figure 23-8 SYS$MOUNT Item Descriptor


Most item descriptors do not have to be in any order. To mount volume sets, you must specify one item descriptor per device and one item descriptor per volume; you must specify the descriptors for the volumes in the same order as the descriptors for the devices on which the volumes are loaded.

For item descriptors other than device and volume names, if you specify the same item descriptor more than once, the last occurrence of the descriptor is used.

The following example illustrates a call to SYS$MOUNT. The call is equivalent to the DCL command that precedes the example.


$ MOUNT/SYSTEM/NOQUOTA  DRA4:,DRA5:  USER01,USER02  USERD$




#include <descrip.h>
#include <lib$routines.h>
#include <mntdef.h>
#include <starlet.h>
#include <stdio.h>
   .
   .
   .


struct {
        unsigned short buflen, item_code;
        void *bufaddr;
        int *retlenaddr;
}itm;

         struct itm itm[7];

main() {
   .
   .
   .
        unsigned int status, flags;

        $DESCRIPTOR(dev1,"DRA4:");
        $DESCRIPTOR(vol1,"USER01");
        $DESCRIPTOR(dev2,"DRA5:");
        $DESCRIPTOR(vol2,"USER02");
        $DESCRIPTOR(log,"USERD$:");

 flags = MNT$M_SYSTEM | MNT$M_NODISKQ;

 i = 0;
 itm[i].buflen = sizeof( flags );
 itm[i].item_code = MNT$_FLAGS;
 itm[i].bufaddr = flags;
 itm[i++].retlenaddr = NULL;

 itm[i].buflen = dev1.dsc$w_length;
 itm[i].item_code = MNT$_DEVNAM;
 itm[i].bufaddr = dev1.dsc$a_pointer;
 itm[i++].retlenaddr = NULL;

 itm[i].buflen = vol1.dsc$w_length;
 itm[i].item_code = MNT$_VOLNAM;
 itm[i].bufaddr = vol1.dsc$a_pointer;
 itm[i++].retlenaddr = NULL;

 itm[i].buflen = dev2.dsc$w_length;
 itm[i].item_code = MNT$_DEVNAM;
 itm[i].bufaddr = dev2.dsc$a_pointer;
 itm[i++].retlenaddr = NULL;

 itm[i].buflen = vol2.dsc$w_length;
 itm[i].item_code = MNT$_VOLNAM;
 itm[i].bufaddr = vol2.dsc$a_pointer;
 itm[i++].retlenaddr = NULL;

 itm[i].buflen = log.dsc$w_length;
 itm[i].item_code = MNT$_LOGNAM;
 itm[i].bufaddr = log.dsc$a_pointer;
 itm[i++].retlenaddr = NULL;

 itm[i].buflen = 0;
 itm[i].item_code = 0;
 itm[i].bufaddr = NULL;
 itm[i++].retlenaddr = NULL;

   .
   .
   .
        status = SYS$MOUNT ( itm );
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL( status );
   .
   .
   .
}

23.18.1.2 Calling the SYS$DISMOU System Service

The SYS$DISMOU system service allows a process to dismount a volume or volume set. When you call SYS$DISMOU, you must specify a device name. If the volume mounted on the device is part of a fully mounted volume set, and you do not specify flags, the whole volume set is dismounted.

The following example illustrates a call to SYS$DISMOU. The call dismounts the volume set mounted in the previous example.



    $DESCRIPTOR(dev1_desc,"DRA4:");
   .
   .
   .
        status = SYS$DISMOU(&dev1_desc); /* devnam - device */
   .
   .
   .

23.18.2 Initializing Volumes

Initializing a volume writes a label on the volume, sets protection and ownership for the volume, formats the volume (depending on the device type), and overwrites data already on the volume.

You interactively initialize a volume from the DCL command stream using the INITIALIZE command. A process can programmatically initialize a volume using the Initialize Volume (SYS$INIT_VOL) system service.

23.18.2.1 Calling the Initialize Volume System Service

You must specify a device name and a new volume name when you call the SYS$INIT_VOL system service. You can also use the itmlst argument of $INIT_VOL to specify options for the initialization. For example, you can specify that data compaction should be performed by specifying the INIT$_COMPACTION item code. See the OpenVMS System Services Reference Manual for more information on initialization options.

Before initializing the volume with SYS$INIT_VOL, be sure you have placed the volume on the device and started the device (by pressing the START or LOAD button).

The default format for files on disk volumes is called Files-11 On-Disk Structure Level 2. Files-11 On-Disk Structure Level 1 format, available on VAX systems, is used by other Compaq operating systems, including RSX-11M, RSX-11M-PLUS, RSX-11D, and IAS, but is not supported on Alpha systems. For more information, see the OpenVMS System Manager's Manual.

Here are two examples of calling SYS$INIT_VOL programmatically: one from a C program and one from a BASIC program.

The following example illustrates a call to SYS$INIT_VOL from Compaq C:



#include <descrip.h>
#include <initdef.h>
#include <lib$routines.h>
#include <starlet.h>
#include <stsdef.h>

struct item_descrip_3
{
    unsigned short buffer_size;
    unsigned short item_code;
    void *buffer_address;
    unsigned short *return_length;
};

main ()
{
    unsigned long
        density_code,
        status;
    $DESCRIPTOR(drive_dsc, "MUA0:");
    $DESCRIPTOR(label_dsc, "USER01");
    struct
    {
        struct item_descrip_3 density_item;
        long terminator;
    } init_itmlst;

    /*
    ** Initialize the input item list.
    */

    density_code = INIT$K_DENSITY_6250_BPI;
    init_itmlst.density_item.buffer_size = 4;
    init_itmlst.density_item.item_code = INIT$_DENSITY;
    init_itmlst.density_item.buffer_address = &density_code;

    init_itmlst.terminator = 0;

    /*
    ** Initialize the volume.
    */

    status = SYS$INIT_VOL (&drive_dsc, &label_dsc, &init_itmlst);

    /*
    ** Report an error if one occurred.
    */

    if (!$VMS_STATUS_SUCCESS (status ))
        LIB$STOP (status);
}

The following example illustrates a call to SYS$INIT_VOL from VAX BASIC:



OPTION TYPE = EXPLICIT

%INCLUDE '$INITDEF' %FROM %LIBRARY

EXTERNAL LONG FUNCTION SYS$INIT_VOL

RECORD ITEM_DESC
        VARIANT
        CASE
            WORD BUFLEN
            WORD ITMCOD
            LONG BUFADR
            LONG LENADR
        CASE
            LONG TERMINATOR
        END VARIANT
END RECORD

DECLARE LONG RET_STATUS, &
    ITEM_DESC INIT_ITMLST(2)

! Initialize the input item list.

INIT_ITMLST(0)::ITMCOD = INIT$_READCHECK
INIT_ITMLST(1)::TERMINATOR = 0

! Initialize the volume.

RET_STATUS = SYS$INIT_VOL ("DJA21:" BY DESC, "USERVOLUME" BY DESC,
INIT_ITMLST() BY REF)

23.19 Formatting Output Strings

When you are preparing output strings for a program, you may need to insert variable information into a string prior to output, or you may need to convert a numeric value to an ASCII string. The Formatted ASCII Output (SYS$FAO) system service performs these functions.

Input to the SYS$FAO system service consists of the following:

  • A control string that contains the fixed text portion of the output and formatting directives. The directives indicate the position within the string where substitutions are to be made, and describe the data type and length of the input values that are to be substituted or converted.
  • An output buffer to contain the string after conversions and substitutions have been made.
  • An optional argument indicating a word to receive the final length of the formatted output string.
  • Parameters that provide arguments for the formatting directives.

The following example shows a call to the SYS$FAO system service to format an output string for a SYS$QIOW macro. Complete details on how to use SYS$FAO, with additional examples, are provided in the description of the SYS$FAO system service in the OpenVMS System Services Reference Manual.




#include <descrip.h>
#include <lib$routines.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#include <stsdef.h>

main() {

        unsigned int status, faolen;
        char faobuf[80];
        $DESCRIPTOR(faostr,"FILE !AS DOES NOT EXIST");    (1)
        $DESCRIPTOR(outbuf, faobuf);                      (2)
        $DESCRIPTOR(filespec,"DISK$USER:MYFILE.DAT");     (3)

        status = SYS$FAO( &faostr, &outlen, &outbuf, &filespec );  (4)
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL(status);
   .
   .
   .
        status = SYS$QIOW( ...faobuf, outlen, ... ); (5)
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL(status);
   .
   .
   .
}
  1. FAOSTR provides the FAO control string. !AS is an example of an FAO directive: it requires an input parameter that specifies the address of a character string descriptor. When SYS$FAO is called to format this control string, !AS will be substituted with the string whose descriptor address is specified.
  2. FAODESC is a character string descriptor for the output buffer; SYS$FAO writes the string into the buffer, and writes the length of the final formatted string in the low-order word of FAOLEN. (A longword is reserved so that it can be used for an input argument to the SYS$QIOW macro.)
  3. FILESPEC is a character string descriptor defining an input string for the FAO directive !AS.
  4. The call to SYS$FAO specifies the control string, the output buffer and length fields, and the parameter P1, which is the address of the string descriptor for the string to be substituted.
  5. When SYS$FAO completes successfully, SYS$QIOW writes the following output string:


    FILE DISK$USER:MYFILE.DAT DOES NOT EXIST
    

23.20 Mailboxes

Mailboxes are virtual devices that can be used for communication among processes. You accomplish actual data transfer by using OpenVMS RMS or I/O services. When the Create Mailbox and Assign Channel (SYS$CREMBX) system service creates a mailbox, it also assigns a channel to it for use by the creating process. Other processes can then assign channels to the mailbox using either the SYS$CREMBX or SYS$ASSIGN system service.

The SYS$CREMBX system service creates the mailbox. The SYS$CREMBX system service identifies a mailbox by a user-specified logical name and assigns it an equivalence name. The equivalence name is a physical device name in the format MBAn, where n is a unit number. The equivalence name has the terminal attribute.

When another process assigns a channel to the mailbox with the SYS$CREMBX or SYS$ASSIGN system service, it can identify the mailbox by its logical name. The service automatically translates the logical name. The process can obtain the MBAn name either by translating the logical name (with the SYS$TRNLNM system service), or by calling the Get Device/Volume Information (SYS$GETDVI) system service to obtain the unit number and the physical device name.

On VAX systems, channels assigned to mailboxes can be either bidirectional or unidirectional. Bidirectional channels (read/write) allow both SYS$QIO read and SYS$QIO write requests to be issued to the channel. Unidirectional channels (read-only or write-only) allow only a read request or a write request to the channel. The unidirectional channels and unidirectional $QIO function modifiers provide for greater synchronization between users of the mailbox.

On VAX systems, the Create Mailbox and Assign Channel (SYS$CREMBX) and Assign I/O Channel (SYS$ASSIGN) system services use the flags argument to enable unidirectional channels. If the flags argument is not specified or is zero, then the channel assigned to the mailbox is bidirectional (read/write). For more information, see the discussion and programming examples in the mailbox driver chapter in the OpenVMS I/O User's Reference Manual. Chapter 3 of this manual also discusses the use of mailboxes.

Mailboxes are either temporary or permanent. You need the user privileges TMPMBX and PRMMBX to create temporary and permanent mailboxes, respectively.

For a temporary mailbox, the SYS$CREMBX service enters the logical name and equivalence name in the logical name table LNM$TEMPORARY_MAILBOX. This logical name table name usually specifies the LNM$JOB logical name table name. The system deletes a temporary mailbox when no more channels are assigned to it.

For a permanent mailbox, the SYS$CREMBX service enters the logical name and equivalence name in the logical name table LNM$PERMANENT_MAILBOX. This logical name table name usually specifies the LNM$SYSTEM logical name table name. Permanent mailboxes continue to exist until they are specifically marked for deletion with the Delete Mailbox (SYS$DELMBX) system service.

The following example shows how processes can communicate by means of a mailbox:



/* Process ORION */

#include <descrip.h>
#include <iodef.h>
#include <lib$routines.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#define MBXBUFSIZ 128
#define MBXBUFQUO 384

/* I/O status block */
struct {
                unsigned short iostat, iolen;
                unsigned int remainder;
}mbxiosb;


main() {
        void *p1, mbxast();
        char mbuffer[MBXBUFSIZ], prmflg=0;
        unsigned short mbxchan, mbxiosb;
        unsigned int status, outlen;
        unsigned int mbuflen=MBXBUFSIZ, bufquo=MBXBUFQUO, promsk=0;
        $DESCRIPTOR(mblognam,"GROUP100_MAILBOX");

/* Create a mailbox */
        status = SYS$CREMBX( prmflg,         /* Permanent or temporary */  (1)
                             &mbxchan,       /* chan - channel number */
                             mbuflen,        /* maxmsg - buffer length */
                             bufquo,         /* bufquo - quota */
                             promsk,         /* promsk - protection mask */
                             0,              /* acmode - access mode */
                             &mblognam,      /* lognam - mailbox logical name */
                             0);             /* flags -  options */
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL(status);
   .
   .
   .
/* Request I/O */
        status = SYS$QIO(0,               /* efn - event flag */   (2)
                          mbxchan,        /* chan - channel number */
                          IO$_READVBLK,   /* func - function modifier */
                          &mbxiosb,       /* iosb - I/O status block */
                          &mbxast,        /* astadr - AST routine */
                          &mbuffer,       /* p1 - output buffer */
                          mbuflen);       /* p2 - length of buffer */
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL(status);
   .
   .
   .

}

void mbxast(void) {                                               (3)

        if (mbxiosb.iostat != SS$_NORMAL)

        status = SYS$QIOW(..., &mbuffer, &outlen,...)
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL(status);

        return;
}


/* Process Cygnus */

#include <descrip.h>
#include <iodef.h>
#include <lib$routines.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#include <stsdef.h>
#define MBXBUFSIZ 128

main() {

        unsigned short int mailchan;
        unsigned int status, outlen;
        char outbuf[MBXBUFSIZ];
        $DESCRIPTOR(mailbox,"GROUP100_MAILBOX");

        status = SYS$ASSIGN(&mailbox, &mailchan, 0, 0, 0);            (4)
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL(status);
   .
   .
   .

        status = SYS$QIOW(0, mailchan, 0, 0, 0, 0, &outbuf, outlen, 0, 0, 0, 0)
        if (!$VMS_STATUS_SUCCESS(status))
                LIB$SIGNAL(status);
   .
   .
   .

}


Previous Next Contents Index