Document revision date: 19 July 1999
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

OpenVMS Programming Concepts Manual


Previous Contents Index

  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.

13.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:

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

13.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); 
} 
 

  1. The item list contains five entries:
  2. The loop repeatedly calls the SYS$DNSW service to read the values of the attribute because the first call might not return all the values. The loop executes until $DNSW returns something other than DNS$_MOREDATA.
  3. The DNS$REMOVE_FIRST_SET_VALUE routine extracts a value from the set.
  4. This attribute name may be the context the routine uses to read additional attributes. The attribute's creation timestamp (CTS), not its value, provides the context.
  5. Finally, display the value in hexadecimal format. (You could also take the attribute name and convert it to a printable format before displaying the result.)

See the discussion about setting confidence in the Guide to Programming with DECdns for information about obtaining up-to-date data on read requests.

13.2.3.3 Enumerating DECdns Names and Attributes

The enumerate functions return DECdns names for objects, child directories, soft links, groups, or attributes in a specific directory. Use either the asterisk (*) or question mark (?) wildcard to screen enumerated items. DECdns matches any single character against the specified wildcard.

Enumeration calls return a set of simple names or attributes. If an enumeration call returns DNS$_MOREDATA, not all matching names or attributes have been enumerated. If you receive this message, use the context-setting conventions that are described for the DNS$_READ_ATTRIBUTE call. You should make further calls, setting DNS$_CONTEXTVARNAME to the last value returned until the procedure returns SS$_NORMAL. For more information, see the SYS$DNS system service in the OpenVMS System Services Reference Manual: A--GETMSG.

The following program, written in C, shows how an application can read the objects in a directory with the SYS$DNS system service. The values that DECdns returns from read and enumerate functions are in different structures. For example, an enumeration of objects returns different structures than an enumeration of child directories. To clarify how to use this data, the sample program demonstrates how to parse any set that the enumerate objects function returns with a run-time library routine in order to remove the first value from the set. The example also demonstrates how the program takes each value from the set.


 
#include <dnsdef.h> 
#include <dnsmsg.h> 
/* 
 * Parameters: 
 *      fname_p   : opaque full name of the directory to enumerate 
 *      fname_len : length of full name of the directory 
 */ 
 
struct $dnsitmdef enumitem[4];            /* Item list for enumeration */ 
unsigned char setbuf[100];                /* Values from enumeration */ 
struct $dnsb enum_iosb;       /* DECdns status information */ 
int synch_event;              /* Used for synchronous AST threads */ 
unsigned short setlen;        /* Length of output in setbuf */ 
 
enumerate_objects(fname_p, fname_len) 
unsigned char *fname_p; 
unsigned short fname_len; 
{ 
    int enumerate_objects_ast(); 
 
    int status;              /* General routine status */ 
    int enum_status;         /* Status of enumeration routine */ 
 
    /* Set up item list */   
 
    enumitem[0].dns$w_itm_code = dns$_directory; /* Opaque directory name */ 
    enumitem[0].dns$w_itm_size = fname_len; 
    enumitem[0].dns$a_itm_address = fname_p; 
 
    enumitem[1].dns$w_itm_code = dns$_outobjects;  /* output buffer */ 
    enumitem[1].dns$a_itm_ret_length = &setlen; 
    enumitem[1].dns$w_itm_size = 100; 
    enumitem[1].dns$a_itm_address = setbuf; 
 
    *((int *)&enumitem[2]) = 0; /* Zero terminate item list */ 
 
    status = lib$get_ef(&synch_event);  (1) 
 
    if(status != SS$_NORMAL) 
    { 
        printf("Could not get event flag to synch AST threads\n"); 
        exit(status);     
    } 
 
    enum_status = sys$dns(0, dns$_enumerate_objects, &enumitem, 
              (2)    &enum_iosb, enumerate_objects_ast, setbuf); 
    
    if(enum_status != SS$_NORMAL)   (3)                  
    { 
        printf("Error enumerating objects = %d\n", enum_status); 
        exit(enum_status); 
    } 
    status = sys$synch(synch_event, &enum_iosb);  (4)
 
    if(status != SS$_NORMAL) 
    { 
        printf("Synchronization with AST threads failed\n"); 
        exit(status); 
    } 
} 
 
/* AST routine parameter:                       */ 
/*      outbuf : address of buffer that contains enumerated names. */ 
                                                 (5)
unsigned char objnamebuf[dns$k_simplenamemax]; /* Opaque object name */ 
 
enumerate_objects_ast(outbuf) 
unsigned char *outbuf; 
{ 
    struct $dnsitmdef cvtitem[3];             /* Item list for class name */ 
    struct $dnsb iosb;        /* Used for name service status information */ 
    struct dsc$descriptor set_dsc, value_dsc, newset_dsc; 
 
    unsigned char simplebuf[dns$k_simplestrmax];   /* Object name string */ 
 
    int enum_status;   /* The status of the enumeration itself */ 
    int status;        /* Used for checking immediate status returns */ 
    int set_status;    /* Status of remove value routine */ 
 
    unsigned short val_len;    /* Length of set value */ 
    unsigned short sname_len;  /* Length of object name */ 
 
    enum_status = enum_iosb.dns$l_dnsb_status;  /* Check status */ 
    if((enum_status != SS$_NORMAL) && (enum_status != DNS$_MOREDATA)) 
    { 
        printf("Error enumerating objects = %d\n", enum_status); 
        sys$setef(synch_event); 
        exit(enum_status); 
    } 
 
    do 
    { 
        /* 
         * Extract object names from output buffer one 
         * value at a time.  Set up descriptors for the extraction. 
         */ 
        set_dsc.dsc$w_length = setlen;    /* Contains address of */ 
        set_dsc.dsc$a_pointer = setbuf;   /* the set whose values */ 
                                          /* are to be extracted */ 
 
        value_dsc.dsc$w_length = dns$k_simplenamemax; 
        value_dsc.dsc$a_pointer = objnamebuf; /* To contain the */ 
                                              /* name of an object */ 
                                              /* after the extraction */ 
 
        newset_dsc.dsc$w_length = 100;      /* To contain a new */ 
        newset_dsc.dsc$a_pointer = setbuf;  /* set structure after */ 
                                            /* the extraction. */ 
 
        /* Call yRTL routine to extract the value from the set */ 
        set_status = dns$remove_first_set_value(&set_dsc, &value_dsc, &val_len, 
                                                0, 0, &newset_dsc, &setlen); 
 
        if(set_status == SS$_NORMAL) 
        {                                   (6)
            cvtitem[0].dns$w_itm_code = dns$_fromsimplename; 
            cvtitem[0].dns$w_itm_size = val_len; 
            cvtitem[0].dns$a_itm_address = objnamebuf; 
 
            cvtitem[1].dns$w_itm_code = dns$_tostringname; 
            cvtitem[1].dns$w_itm_size = dns$k_simplestrmax; 
            cvtitem[1].dns$a_itm_address = simplebuf; 
            cvtitem[1].dns$a_itm_ret_length = &sname_len; 
 
            *((int *)&cvtitem[2]) = 0; 
 
            status = sys$dnsw(0, dns$_simple_opaque_to_string, &cvtitem, 
                              &iosb, 0, 0); 
                                                                        
            if(status == SS$_NORMAL) 
                status = iosb.dns$l_dnsb_status;  /* Check for errors */ 
 
            if(status != SS$_NORMAL) /* If error, terminate processing */ 
            { 
                printf("Converting object name to string returned %d\n", 
                       status); 
                exit(status); 
            } 
            else 
            { 
                printf("%.*s\n", sname_len,simplebuf); 
            } 
 
            enumitem[2].dns$w_itm_code = dns$_contextvarname;   (7)
            enumitem[2].dns$w_itm_size = val_len; 
            enumitem[2].dns$a_itm_address = objnamebuf; 
 
            *((int *)&enumitem[3]) = 0; 
        } 
        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); 
 
    if(enum_status == DNS$_MOREDATA) 
    {                                              (8)
        enum_status = sys$dns(0, dns$_enumerate_objects, &enumitem, 
                               &enum_iosb, enumerate_objects_ast, setbuf); 
 
        if(enum_status != SS$_NORMAL)  /* Check status of $DNS */ 
        { 
            printf("Error enumerating objects = %d\n", enum_status); 
            sys$setef(synch_event); 
        } 
    }  
    else 
    {                                               (9)
        sys$setef(synch_event); 
    } 
} 
 

  1. Get an event flag to synchronize the execution of AST threads.
  2. Use the system service to enumerate the object names.
  3. Check the status of the system service itself before waiting for threads.
  4. Use the SYS$SYNCH call to make sure the DECdns Clerk has completed and that all threads have finished executing.
  5. After enumerating objects, SYS$DNS calls an AST routine. The routine shows how DNS$REMOVE_FIRST_SET_VALUE extracts object names from the set returned by the DNS$_ENUMERATE_OBJECTS function.
  6. Use an item list to convert the opaque simple name to a string name so you can display it to the user. The item list contains the following entries:
  7. This object name may provide the context for continuing the enumeration. Append the context variable to the item list so the enumeration can continue from this name if there is more data.
  8. Use the system service to enumerate the object names as long as there is more data.
  9. Set the event flag to indicate that all AST threads have completed and that the program can terminate.

13.3 Using the DCL Command DEFINE with DECdns Logical Names

When the DECdns Clerk is started on the operating system, the VAX system creates a unique logical name table for DECdns to use in translating full names. This logical name table, called DNS$SYSTEM, prevents unintended interaction with other system logical names.

To define systemwide logical names for DECdns objects, you must have the appropriate privileges to use the DCL command DEFINE. Use the DEFINE command to create the logical RESEARCH.PROJECT_DISK, for example, by entering the following DCL command:


$ DEFINE/TABLE=DNS$SYSTEM RESEARCH "ENG.RESEARCH"

When parsing a name, the SYS$DNS service specifies the logical name DNS$LOGICAL as the table it uses to translate a simple name into a full name. This name translates to DNS$SYSTEM (by default) to access the systemwide DECdns logical name table.

To define process or job logical names for SYS$DNS, you must create a process or job table and redefine DNS$LOGICAL as a search list, as in the following example (note that elevated privileges are required to create a job table):


$ CREATE /NAME_TABLE DNS_PROCESS_TABLE
$ DEFINE /TABLE=LNM$PROCESS_DIRECTORY DNS$LOGICAL -
_$DNS_PROCESS_TABLE,DNS$SYSTEM

Once you have created the process or job table and redefined DNS$LOGICAL, you can create job-specific logical names for DECdns by using the DCL command DEFINE, as follows:


$ DEFINE /TABLE=DNS_PROCESS_TABLE RESEARCH "ENG.RESEARCH.MYGROUP"


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
5841PRO_037.HTML