Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

## Appendix F
Distributed Name Service (VAX Only)

This chapter describes the Digital Distributed Name Service (DECdns) Clerk by introducing the functions of the DECdns (SYS$DNS) system service and various run-time library routines. It is divided into the following sections:

Section F.1 describes how to use the portable application programming interface and the operating system's system service and run-time library interface.

Section F.2 describes how to use the SYS$DNS system service.

Section F.3 describes how to use the DCL command DEFINE.

## F.1 DECdns Clerk System Service

The DECdns Clerk (SYS$DNS) system service provides applications with a means of assigning networkwide names to system resources. Applications can use DECdns to name such resources as printers, files, disks, nodes, servers, and application databases. Once an application has named a resource using DECdns, the name is available for all users of the application.

The SYS$DNS system service supports two programming interfaces:

- Portable application programming interface
- System service and run-time library (RTL)

Portable Application Interface

Application designers should select an interface for their application based on programming language, application base, and the specific requirements of their application.

The portable interface provides support for applications written in the C programming language, and it provides a high-level interface with easy-to-use methods of creating and maintaining DECdns names. Use the portable interface for applications that must be portable between VAX systems and the Compaq Tru64 UNIX operating system.

The portable interface is documented in the Guide to Programming with DECdns.

VAX System Services and RTL Routines

The VAX system services and run-time library routines can be used by applications written in the high-level and midlevel languages listed in the preface of this document. However, applications that use these interfaces are limited to the VAX system environment. Use the system service when an application meets any of the following requirements:

- The application needs the full capabilities, flexibility, and functions of asynchronous support.
- The application will run as part of a privileged shareable image on the operating system.
- The application is not written in the C programming language.

The SYS$DNS system service is documented in the OpenVMS System Services Reference Manual. Before using this system service, familiarize yourself with the basic operating principles, terms, and definitions used by DECdns. You can gain a working knowledge of DECdns by reading about the following topics in the Guide to Programming with DECdns:

- DECdns component operation
- Namespace directories, objects, soft links, groups, and clearinghouses
- DECdns name syntax
- Attributes
- Clerk caching
- Setting confidence and timeouts
- Recommendations for DECdns application programmers

By understanding these topics, you can proceed more easily with this chapter, which provides an introduction to the DECdns system service and run-time library routines and discusses the following topics:

- Functions provided by the service and routines
- How to use the SYS$DNS system service

### F.1.1 Using the DECdns System Service and Run-Time Library Routines

You can use the SYS$DNS system service and run-time library routines together to assign, maintain, and retrieve DECdns names. This section describes the capabilities of each interface.

#### F.1.1.1 Using the SYS$DNS System Service

DECdns provides a single system service call (SYS$DNS) to create, delete, modify, and retrieve DECdns names from a namespace. The SYS$DNS system service completes asynchronously; that is, it returns to the client immediately after making a name service call. The status returned to the client indicates whether a request was queued successfully to the name service.

The SYS$DNSW system service is the synchronous equivalent of SYS$DNS. The SYS$DNSW call is identical to SYS$DNS in every way except that SYS$DNSW returns to the caller after the operation completes.

The SYS$DNS call has two main parameters:

- A function code that identifies the particular service to perform
- An item list that specifies all the parameters for the required function

The system service provides the following functions:

- Create and delete DECdns names in the namespace
- Enumerate DECdns names in a particular directory
- Add, read, remove, and test attributes and attribute values
- Add, create, remove, restore, and update directories
- Create, remove, and resolve soft links
- Create and remove groups
- Add, remove, and test members in a group
- Parse names to convert string format names to DECdns opaque format names and back to string

You specify item codes as either input or output parameters in the item list. Input parameters modify functions, set context, or describe the information to be returned. Output parameters return the requested information.

You can specify the following in input item codes:

- An attribute name and type
- The class of a DECdns name and, optionally, a class filter
- The class version of a DECdns name
- A confidence setting to indicate whether the request should be serviced from the clerk's cache or from a server
- An indication that the application will repeat a read call, which forces caching of recently read data
- A name or timestamp that sets the context from which to begin or restart enumerating or reading
- The name and type of an object, directory, group, member, clearinghouse, or soft link, and the ability to suppress the namespace nickname from the full name
- A simple or full name in opaque or string format
- A request to search subgroups for a member
- An operation, either adding or deleting an attribute
- A value for an attribute
- A pointer to the address of the next character in a full or simple name
- A timeout period to wait for a call to complete
- An expiration time and extension time for soft links

The output item codes return the following information:

- A creation timestamp for an object
- A set of child directories, soft links, attribute names, attribute values, or object names
- An opaque simple or full name
- A string name and length
- A resolved soft link
- A name or timestamp context variable that indicates the last directory, object, soft link, or attribute that was enumerated or read

#### F.1.1.2 Using the Run-Time Library Routines

You can use the DECdns run-time library routines to manipulate output from the SYS$DNS system service. The routines provide the following functions:

- Remove a value from a set returned by an enumeration or read system service function
- Compare, append, concatenate, and count opaque names that were created with the system service
- Convert addresses

To read a single attribute value using the system service and run-time library routines, use the following routines:

- DNS$_ENUMERATE_OBJECTS function code to enumerate objects
- DNS$REMOVE_FIRST_SET_VALUE run-time library routine to remove the first set value
- DNS$_READ_ATTRIBUTE function code to read the first set value

You can also use the system service and run-time library routines together to add an opaque simple name to a full name by performing the following steps:

1. Obtain a string full name from a user.
2. Use the system service DNS$_PARSE_FULLNAME_STRING function code to convert the string name to opaque format.
3. Use the DNS$_APPEND_SIMPLE_TO_RIGHT run-time library routine to add an opaque simple name to the end of the full name.

## F.2 Using the SYS$DNS System Service Call

The following sections describe how to create and modify an object, and then how to read attributes and enumerate names and attributes in the namespace.

Each section contains a code example. These code examples are all contained in the sample program that resides on your distribution medium under the file name SYS$EXAMPLES:SYS$DNS_SAMPLE.C.

### F.2.1 Creating Objects

Applications that use DECdns can create an object in the namespace for each resource used by the application. You can create objects using either the SYS$DNS or the SYS$DNSW system service.

A DECdns object consists of a name and its associated attributes. When you create the object, you must assign a class and a class version. You can modify the object to hold additional attributes, such as class-specific attributes, on an as-needed basis.

Note that applications can use objects that are created by other applications.

To create an object in the namespace with SYS$DNS:

1. Prompt the user for a name.
   The name that an application assigns to an object should come from a user, a configuration file, a system logical name, or some other source. The application never assigns an object's name because the namespace structure is uncertain. The name the application receives from the user is in string format.
2. Use the SYS$DNS parse function to convert the full name string into an opaque format. Specify the DNS$_NEXTCHAR_PTR item code to obtain the length of the opaque name.
3. Optionally, reserve an event flag so you can check for completion of the service.
4. Build an item list that contains the following elements:
   - The opaque name for the object (resulting from the translation in step 2)
   - The class name given by the application, which should contain the facility code
   - The class version assigned by the application
   - An optional timeout value that specifies when the call expires
5. Optionally, provide the address of the DECdns status block to receive status information from the name service.
6. Optionally, provide the address of the asynchronous system trap (AST) service routine. AST routines allow a program to continue execution while waiting for parts of the program to complete.
7. Optionally, supply a parameter to pass to the AST routine.
8. Call the create object function and provide all the parameters supplied in steps 1 through 7.

If a clerk call is not complete when timeout occurs, then the call completes with an error. The error is returned in the DECdns status block.

An application should check for errors that are returned; it is not enough to check the return of the SYS$DNS call itself. You need to check the DECdns status block to be sure no errors are returned by the DECdns server.

The following routine, written in C, shows how to create an object in the namespace with the synchronous service SYS$DNSW. The routine demonstrates how to construct an item list.

    #include <dnsdef.h>
    #include <dnsmsg.h>
    /*
     * Parameters:
     *      class_name = address of the opaque simple name of the class
     *                   to assign to the object
     *      class_len  = length (in bytes) of the class opaque simple name
     *      object_name= address of opaque full name of the object
     *                   to create in the namespace.
     *      object_len = length (in bytes) of the opaque full name of the
     *                   object to create
     */

    create_object(class_name, class_len, object_name, object_len)
    unsigned char *class_name;  /*Format is a DECdns opaque simple name*\
    unsigned short class_len;
    unsigned char *object_name; /*Format is a DECdns opaque simple name*\
    unsigned short object_len;
    {
        struct $dnsitmdef createitem[4]; /* Item list used by system service */
        struct $dnscversdef version;     /* Version assigned to the object */
        struct $dnsb iosb;          /* Used to determine DECdns server status */
        int status;                 /* Status return from system service */

        /*
         * Construct the item list that creates the object:
         */
        createitem[0].dns$w_itm_size = class_len;   (1)
        createitem[0].dns$w_itm_code = dns$_class;
        createitem[0].dns$a_itm_address = class_name;

        createitem[1].dns$w_itm_size = object_len;   (2)
        createitem[1].dns$w_itm_code = dns$_objectname;
        createitem[1].dns$a_itm_address = object_name;

        version.dns$b_c_major = 1;   (3)
        version.dns$b_c_minor = 0;

        createitem[2].dns$w_itm_size = sizeof(struct $dnscversdef);  (4)
        createitem[2].dns$w_itm_code = dns$_version;
        createitem[2].dns$a_itm_address = &version;

        *((int *)&createitem[3]) = 0;   (5)

        status = sys$dnsw(0, dns$_create_object, &createitem, &iosb, 0, 0); (6)

        if(status == SS$_NORMAL)
        {
            status = iosb.dns$l_dnsb_status; (7)
        }

        return(status);
    }

1. The first entry in the item list is the address of the opaque simple name that represents the class of the object.
2. The second entry is the address of the opaque full name for the object.
3. The next step is to build a version structure that indicates the version of the object. In this case, the object is version 1.0.
4. The third entry is the address of the version structure that was just built.
5. A value of 0 terminates the item list.
6. The next step is to call the system service to create the object.
7. Check to see that both the system service and DECdns were able to perform the operation without error.

### F.2.2 Modifying Objects and Their Attributes

After you create objects that identify resources, you can add or modify attributes that describe properties of the object. There is no limit imposed on the number of attributes an object can have.

You modify an object whenever you need to add an attribute or attribute value, change an attribute value, or delete an attribute or attribute value. When you modify an attribute, DECdns updates the timestamp contained in the DNS$UTS attribute for that attribute.

To modify an attribute or attribute value, use the DNS$_MODIFY_ATTRIBUTE function code. Specify the attribute name in the input item code along with the following required input item codes:

- DNS$_ATTRIBUTETYPE to specify a set-valued (DNS$K_SET) or single-valued (DNS$K_SINGLE) attribute
- DNS$_MODOPERATION to specify that the value is being added (DNS$K_PRESENT) or deleted (DNS$K_ABSENT)

Use the DNS$_MODVALUE item code to specify the value of the attribute. Note that the DNS$_MODVALUE item code must be specified to add a single-valued attribute. You can specify a null value for a set-valued attribute. DECdns modifies attribute values in the following way:

- If the attribute exists and you specify an attribute value, the attribute value is removed from a set-valued attribute. All other values are unaffected. For a single-valued attribute, DECdns removes the attribute and its value from the name.
- If you do not specify an attribute value, DECdns removes the attribute and all values of the attribute for both set-valued and single-valued attributes.

To delete an attribute, use the DNS$_MODOPERATION item code.

The following is an example of how to use the DNS$_MODIFY_ATTRIBUTE function code to add a new member to a group object. To do this, you add the new member to the DNS$Members attribute of the group object. Use the following function codes:

- Specify the group object (DNS$_ENTRY) and type (DNS$_LOOKINGFOR). The type should be specified as object (DNS$K_OBJECT).
- Use DNS$_MODOPERATION to add a member to the DNS$Members attribute (DNS$_ATTRIBUTENAME), which is a set-valued attribute (DNS$_ATTRIBUTETYPE).
- Specify the new member object name in DNS$_MODVALUE.
- Use another DNS$_MODIFY_ATTRIBUTE call to assign access rights for the new member to the DNS$ACS attribute of the member object.

Perform the following steps to modify an object with SYS$DNSW:

1. Build an item list that contains the following elements:
   - Opaque name of the object you are modifying
   - Type of object
   - Operation to perform
   - Type of attribute you are modifying
   - Attribute name
   - Value being added to the attribute
2. Supply any of the optional parameters described in Section F.2.1.
3. Call the modify attribute function, supplying the parameters established in steps 1 and 2.

The following example, written in C, shows how to add a set-valued attribute and a value to an object:

    #include <dnsdef.h>
    #include <dnsmsg.h>
    /*
     * Parameters:
     *      obj_name = address of opaque full name of object
     *      obj_len  = length of opaque full name of object
     *      att_name = address of opaque simple name of attribute to create
     *      att_len  = length of opaque simple name of attribute
     *      att_value= value to associate with the attribute
     *      val_len  = length of added value (in bytes)
     */

    add_attribute(obj_name, obj_len, att_name, att_len, att_value, val_len)
    unsigned char *obj_name;
    unsigned short obj_len;
    unsigned char *att_name;
    unsigned short att_len;
    unsigned char *att_value;
    unsigned short val_len;

    main() {
            struct $dnsitmdef moditem[7];          /* Item list for $DNSW */
            unsigned char objtype = dns$k_object;  /* Using objects */
            unsigned char opertype = dns$k_present; /* Adding an object */
            unsigned char attype = dns$k_set;     /* Attribute will be type set */
            struct $dnsb iosb;                /* Used to determine DECdns status */
            int status;                       /* Status of system service */

        /*
         * Construct the item list to add an attribute to an object.
         */
        moditem[0].dns$w_itm_size = obj_len;
        moditem[0].dns$w_itm_code = dns$_entry;
        moditem[0].dns$a_itm_address = obj_name;   (1)

        moditem[1].dns$w_itm_size = sizeof(char);
        moditem[1].dns$w_itm_code = dns$_lookingfor;
        moditem[1].dns$a_itm_address = &objtype;   (2)

        moditem[2].dns$w_itm_size = sizeof(char);
        moditem[2].dns$w_itm_code = dns$_modoperation;
        moditem[2].dns$a_itm_address = &opertype;   (3)

        moditem[3].dns$w_itm_size = sizeof(char);
        moditem[3].dns$w_itm_code = dns$_attributetype;
        moditem[3].dns$a_itm_address = &attype;   (4)

        moditem[4].dns$w_itm_size = att_len;
        moditem[4].dns$w_itm_code = dns$_attributename;
        moditem[4].dns$a_itm_address = att_name;   (5)

        moditem[5].dns$w_itm_size = val_len;
        moditem[5].dns$w_itm_code = dns$_modvalue;
        moditem[5].dns$a_itm_address = att_value;   (6)

        *((int *)&moditem[6]) = 0;   (7)

        /*
         * Call $DNSW to add the attribute to the object.
         */
        status = sys$dnsw(0, dns$_modify_attribute, &moditem, &iosb, 0, 0);(8)

        if(status == SS$_NORMAL)
        {
        status = iosb.dns$l_dnsb_status;  (9)
        }

        return(status);
    }

1. The first entry in the item list is the address of the opaque full name of the object.
2. The second entry shows that this is an object, not a soft link or child directory pointer.
3. The third entry is the operation to perform. The program adds an attribute with its value to the object.
4. The fourth entry is the attribute type. The attribute has a set of values rather than a single value.
5. The fifth entry is the opaque simple name of the attribute being added.
6. The sixth entry is the value associated with the attribute.
7. A value of 0 terminates the item list.
8. A call is made to the SYS$DNSW system service to perform the operation.
9. A check is made to see that both the system service and DECdns performed the operation without error.

### F.2.3 Requesting Information from DECdns

Once an application adds its objects to the namespace and modifies the names to contain all necessary attributes, the application is ready to use the namespace. An application can request that the DECdns Clerk either read attribute information stored with an object or list all the application's objects that are stored in a particular directory. An application might also need to resolve all soft links in a name in order to identify a target.

To request information from DECdns, use the read or enumerate function codes, as follows:

- The DNS$_READ_ATTRIBUTE function reads and returns a set whose members are the values of the specified attribute.
- The DNS$_ENUMERATE functions return a list of names for attributes, child directories, objects, and soft links.

#### F.2.3.1 Using the Distributed File Service (DFS)

The VAX Distributed File Service (DFS) uses DECdns for resource naming. This section gives an example of the DNS$_READ_ATTRIBUTE call as used by DFS. The DFS application uses DECdns to give the operating system's users the ability to use remote operating system disks as if the disks were attached to their local VAX system. The DFS application creates DECdns names for the operating system's directory structures (a directory and all of its subdirectories). Each DFS object in the namespace references a particular file access point. DFS creates each object with a class attribute of DFS$ACCESSPOINT and modifies the address attribute (DNS$Address) of each object to hold the DECnet node address where the directory structures reside. As a final step in registering its resources, DFS creates a database that maps DECdns names to the appropriate operating system directory structures.

Whenever the DFS application receives the following mount request, DFS sends a request for information to the DECdns Clerk:

`MOUNT ACCESS_POINT dns-name vms-logical-name`

To read the address attribute of the access point object, the DFS application performs the following steps:

1. Translates the DECdns name that is supplied through the user to opaque format using the SYS$DNS parse function
2. Reads the class attribute of the object with the $DNS read attribute function, indicating that there is a second call to read other attributes of the object
3. Makes a second call to the SYS$DNS read attribute function to read the address attribute of the object
4. Sends the DECdns name to the DFS server, which looks up the disk on which the access point is located
5. Verifies that the DECdns name is valid on the DFS server

The DFS client and DFS server now can communicate to complete the mount function.

#### F.2.3.2 Reading Attributes from DNS

When requesting information from DNS, an application always takes an object name from the user, translates the name into opaque format, and passes it in an item list to the DECdns Clerk.

Each read request returns a set of attribute values. The DNS$_READ_ATTRIBUTE service uses a context item code called DNS$_CONTEXTVARTIME to maintain context when reading the attribute values. The context item code saves the last member that is read from the set. When the next read call is issued, the item code sets the context to the next member in the set, reads it, and returns it. The context item code treats single-valued attributes as though they were a set of one.

If an enumeration call returns DNS$_MOREDATA, not all matching names or attributes have been enumerated. If you receive this message, you should make further calls, setting DNS$_CONTEXTVARTIME to the last value returned until the procedure returns SS$_NORMAL.

The following program, written in C, shows how an application reads an object attribute. The SYS$DNSW service uses an item list to return a set of objects. Then the application calls a run-time library routine to read each value in the set.

    #include <dnsdef.h>
    #include <dnsmsg.h>
    /*
     * Parameters:
     *      opaque_objname = address of opaque full name for the object
     *                       containing the attribute to be read
     *      obj_len        = length of opaque full name of the object
     *      opaque_attname = address of the opaque simple name of the
     *                       attribute to be read
     *      attname_len    = length of opaque simple name of attribute
     */

    read_attribute(opaque_objname, obj_len, opaque_attname, attname_len)
    unsigned char *opaque_objname;
    unsigned short obj_len;
    unsigned char *opaque_attname;
    unsigned short attname_len;
    {
        struct $dnsb iosb;             /* Used to determine DECdns status */
        char objtype = dns$k_object;   /* Using objects */

        struct $dnsitmdef readitem[6]; /* Item list for system service */
        struct dsc$descriptor set_dsc, value_dsc, newset_dsc, cts_dsc;

        unsigned char attvalbuf[dns$k_maxattribute]; /* To hold the attribute */
                                  /* values returned from extraction routine. */
        unsigned char attsetbuf[dns$k_maxattribute]; /* To hold the set of    */
                              /* attribute values after the return from $DNSW. */
        unsigned char ctsbuf[dns$k_cts_length];     /* Needed for context of multiple reads */

        int read_status;         /* Status of read attribute routine */
        int set_status;          /* Status of remove value routine */
        int xx;                  /* General variable used by print routine */

        unsigned short setlen;   /* Contains current length of set structure */
        unsigned short val_len;  /* Contains length of value extracted from set */
        unsigned short cts_len;  /* Contains length of CTS extracted from set */

        /* Construct an item list to read values of the attribute. */ (1)
        readitem[0].dns$w_itm_code = dns$_entry;
        readitem[0].dns$w_itm_size = obj_len;
        readitem[0].dns$a_itm_address = opaque_objname;

        readitem[1].dns$w_itm_code = dns$_lookingfor;
        readitem[1].dns$w_itm_size = sizeof(char);
        readitem[1].dns$a_itm_address = &objtype;

        readitem[2].dns$w_itm_code = dns$_attributename;
        readitem[2].dns$a_itm_address = opaque_attname;
        readitem[2].dns$w_itm_size = attname_len;

        readitem[3].dns$w_itm_code = dns$_outvalset;
        readitem[3].dns$a_itm_ret_length = &setlen;
        readitem[3].dns$w_itm_size = dns$k_maxattribute;
        readitem[3].dns$a_itm_address = attsetbuf;

        *((int *)&readitem[4]) = 0;

        do   (2)
        {
            read_status = sys$dnsw(0, dns$_read_attribute, &readitem, &iosb, 0, 0);

            if(read_status == SS$_NORMAL)
            {
                read_status = iosb.dns$l_dnsb_status;
            }

            if((read_status == SS$_NORMAL) || (read_status == DNS$_MOREDATA))
            {
                do
                {
                    set_dsc.dsc$w_length = setlen;
                    set_dsc.dsc$a_pointer = attsetbuf; /* Address of set */

                    value_dsc.dsc$w_length = dns$k_simplenamemax;
                    value_dsc.dsc$a_pointer = attvalbuf;  /* Buffer to hold  */
                                                          /* attribute value */

                    cts_dsc.dsc$w_length = dns$k_cts_length;
                    cts_dsc.dsc$a_pointer = ctsbuf; /* Buffer to hold value's CTS*/

                    newset_dsc.dsc$w_length = dns$k_maxattribute;
                    newset_dsc.dsc$a_pointer = attsetbuf; /* Same buffer for */
                                                          /* each call      */

                    set_status = dns$remove_first_set_value(&set_dsc, &value_dsc,
                                 (3)                  &val_len, &cts_dsc,
                                                            &cts_len, &newset_dsc,
                                                            &setlen);

                    if(set_status == SS$_NORMAL)
                    {   (4)
                        readitem[4].dns$w_itm_code = dns$_contextvartime;
                        readitem[4].dns$w_itm_size = cts_len;
                        readitem[4].dns$a_itm_address = ctsbuf;

                        *((int *)&readitem[5]) = 0;

                        printf("\tValue: ");   (5)
                        for(xx = 0; xx < val_len; xx++)
                            printf("%x ", attvalbuf[xx]);
                        printf("\n");
                    }
                    else if (set_status != 0)
                    {
                        printf("Error %d returned when removing value from set\n",
                               set_status);
                        exit(set_status);
                    }
                } while(set_status == SS$_NORMAL);
            }
            else
            {
                printf("Error reading attribute = %d\n", read_status);
                exit(read_status);
            }
        } while(read_status == DNS$_MOREDATA);
    }

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_093.HTML