Compaq ACMS for OpenVMS
Remote Systems Management Guide

Previous Contents Index

Chapter 6
Management Programming Using ONC RPC

Programmers who want to access and maintain the ACMS Remote Manager from their own programs can use the following two interfaces:

This chapter describes the ONC RPC interface. Programmers who are familiar with the C programming language and RPC mechanisms can use this information when coding and building their own client programs. For a more complete discussion of ONC RPC programming, see Power Programming with RPC by John Bloomer, published by O'Reilly & Associates, Inc., Sebastopol, CA.

6.1 ONC RPC Overview

ONC RPC is a widely used and supported remote procedure call (RPC) mechanism. Similar to other RPC mechanisms, the ONC RPC protocol supports a request/response model, in which client applications make requests of servers and receive responses. Clients typically make synchronous calls to remote servers over a network. The RPC mechanism hides the network operations from the programmer, making each remote procedure call appear to be a local function invocation.

Unlike the SNMP interface, which connects to the ACMS Remote Manager using the SNMP master agent, access through ONC RPC is directly to the ACMS Remote Manager.

Figure 6-1 provides a graphical overview of the ONC RPC interface.

Figure 6-1 ONC RPC Interface Overview

Programming for ONC RPC is based on interface definitions coded in Interface Definition Language (IDL). Functions and their arguments are described in IDL source files, which are precompiled using an IDL compiler. The outputs from the IDL compiler are a set of C source and header files that are then compiled and linked with client and server programs to form run-time executables. (For Remote Manger client development, server stub files are not needed and can be discarded.)

Figure 6-2 provides a graphical overview of programming for ONC RPC.

Figure 6-2 ONC RPC Programming Overview

The IDL that describes the procedures supported by the ACMS Remote Manager is provided with the ACMS Remote Manager installation and provides the basis for ACMS management programming. Users write their own client programs, calling the functions described in the ACMS Remote Manager IDL file (ACMSMGMT_RPC.X). They precompile the IDL file with the precompiler provided by their TCP/IP package, and then compile and link their client programs. No compilation or linking is required for the Remote Manager; it contains all the support required by ONC RPC client programs.

The ACMS Remote Manager provides several types of procedures that are callable through the ONC RPC interface. These procedures provide read and write access to each table maintained by the Remote Manager, as well as command routines (such as start and stop). Table 6-1 summarizes the types of procedures available.

Table 6-1 Procedures for Accessing Remote Manager Functions
Procedure Type Table or Object Description
Add Collection, Error Filter, Trap Allows entries to be added to configuration tables.
Delete Collection, Error Filter, Trap Allows entries to be removed from configuration tables.
Get ACC, Error Filter, Manager (MGR) Status, Parameters, QTI, TSC, Version Returns all columns in the table.
List Collection, CP, Error Data, EXC, Interfaces, Log, Process, Server, Task Group, Trap, Users Returns a linked list of records based on selection criteria. All columns in the table are returned with each row.
Replace Server Allows an application server to be replaced.
Reset Error Data, Log Allows the current version of the Remote Manager log or error log to be closed and a new version to be opened.
Save Error Filter Saves the current error filter records for a specific node and writes them to an error filter file.
Set ACC, Collection, CP, EXC, Interfaces, Parameters, QTI, Server, Trap, TSC Allows modifications to the table. For configuration tables, set functions allow rows to be added to tables. (Entity rows can only be added by starting the appropriate process.)
Start ACC, EXC, QTI, Trace Monitor, TSC Allows ACMS processes to be started.
Stop Manager, ACC, EXC, QTI, TSC, Trace Monitor Allows ACMS processes to be stopped.

The procedure names and arguments for each procedure type are similar --- all get calls have similar names and arguments; set calls have similar names and arguments, and so on.

The sections that follow describe in more detail how to write programs that access these functions.

6.2 Building Multithreaded Clients

The file ACMS$MGMT_EXAMPLES_BUILD.COM describes how to use the client stub provided with the Remote Manager when compiling and linking your application. The sample procedures provided in ACMS$MGMT_EXAMPLES.C are designed to use the thread-safe client stub, and as a result, each procedure contains one or more "free" calls (to prevent memory leaks).

To implement a non-thread safe client using the RPC-generated stub, omit the "free" calls. See ACMS$MGMT_EXAMPLES_BUILD.COM for detailed build instructions.

6.3 API Overview

Remote management client programs follow a typical programming model that involves the following phases:

6.4 Initialization and Security

In order to perform initialization, ACMS remote client programs must first determine the type of authentication (explicit or implicit) they will use. The type of authentication determines whether or not the client program must obtain credentials.

The Remote Manager performs authentication either explicitly, using a valid OpenVMS account name and password, or implicitly, using ACMS proxies. Implicit authentication is allowed only if it has been enabled on the Remote Manager node, and does not require the use of credentials. Explicit authentication requires the use of credentials and also requires that the client process execute a separate login using the ACMSMGR utility.

See Section 4.4 for a discussion of the various security modes and how to log in using ACMSMGR.

Once the authentication mode has been determined, remote management clients perform the following tasks:

6.4.1 Initialization Example

The following example code shows a client program that establishes an RPC connection with the Remote Manager, establishes the security context, and then populates it with credentials information if a logical name (ACMS$MGMT_USER) has been defined.

#include <rpc/rpc.h> 
#include string 
#include "acmsmgmt_rpc.h" 
CLIENT *cl; 
char sname[] = "sparks"; 
char *username_p, username[13] = ""; 
int client_id; 
int status; 
int acms$mgmt_get_creds(); 
int main () 
    /* if the logical is defined, credential information will be used */ 
    username_p = getenv("ACMS$MGMT_USER"); 
    if (username_p) 
    /* establish an rpc connection to the server */ 
    cl = clnt_create(sname, ACMSMGMT_RPC, ACMSMGMT_VERSION, "tcp"); 
    /* if the connection was established */ 
    if (cl != NULL) { 
 /* create a security context */ 
        cl->cl_auth = authunix_create_default(); 
        client_id = 0; 
 /* optionally, get credentials for this user & server */ 
        if (strlen(username)) 
           status = acms$mgmt_get_creds(sname,username,&client_id); 

6.5 Get Procedures

Get procedures are available for all ACMS Remote Manager tables. Get procedures return all columns from a single table row.

As Table 6-2 shows, a separate get procedure is available for each entity and table.

Input arguments to get procedures are client_id. See Chapter 8 for details about each call.

Table 6-2 Get Procedures
Procedure Description
acmsmgmt_get_acc_2 No keys; only 1 ACC per node.
acmsmgmt_get_err_filter_2 No keys; only 1 Error Filter per node.
acmsmgmt_get_mgr_status_1 No keys; only one row in the Manager Status table.
acmsmgmt_get_param_2 No keys; only one row in the Parameter table.
acmsmgmt_get_qti_2 No keys; only 1 QTI per node.
acmsmgmt_get_tsc_2 No keys; only 1 TSC per node.
acmsmgmt_get_version_2 No keys; only 1 version per node.

6.5.1 Get Example

The following example code shows how a client program calls the acmsmgmt_get_param_2 procedure and displays the current value of a parameter.

int get_param_data(int client_id,CLIENT *cl) 
   int x = 0; 
   int y = 0; 
   param_rec2       *params; 
   param_rec_out2   *param_rec; 
   static struct sub_id_struct sub_rec; 
   int status; 
   sub_rec.client_id = client_id; 
   param_rec = acmsmgmt_get_param_2(&sub_rec,cl); 
   if (!param_rec) { 
      printf("\n RPC Call to get Parameter data failed"); 
   if (param_rec->status != MGMT_SUCCESS) { 
      printf("\n Call to get Parameter data failed, returning status code %d", 
      status = param_rec->status; 
        xdr_free(xdr_param_rec_out2, param_rec); 
   params = &param_rec->; 
      printf("\n Maximum logins allowed is %d",params->max_logins); 
        xdr_free(xdr_param_rec_out2, param_rec); 

6.6 List Procedures

List procedures operate on all rows in a table. Procedures are available for each entity and each configuration table with more than one row. There are no list procedures for the following tables, since they contain only one row:

As Table 6-3 shows, separate list procedures are provided for the remainder of the management information and configuration tables. Input to a list procedure is a selection criteria record, which varies depending on the table being accessed. Some key values in the selection criteria records support wildcards (*, %).

Table 6-3 List Procedures
Procedure Description
acmsmgmt_list_collections_2 Key value is table index.
acmsmgmt_list_cp_2 No keys.
acmsmgmt_list_err_2 No keys.
acmsmgmt_list_err_filter_2 No keys.
acmsmgmt_list_exc_2 Key value is application name or table index.
acmsmgmt_list_interfaces_1 No keys.
acmsmgmt_list_log_1 No keys; selection criteria is before_time, since_time, file_name, facility, severity.
acmsmgmt_list_proc_1 No keys.
acmsmgmt_list_server_1 Key value is application name, server name, or table index.
acmsmgmt_list_tg_2 Key value is application name, task group name, or table index.
acmsmgmt_list_trap_1 No keys.
acmsmgmt_list_users_1 No keys.

For all list procedures, only entire rows (that is, all columns in the row) are returned. Data is returned in a linked list. The number of nodes in the list is determined by the systemwide parameter table field max_rpc_return_recs. When the number of rows to be returned exceeds the value of max_rpc_return_recs, the caller must reissue the call, providing the appropriate key values to fetch the next set of rows. The call returns status MGMT_NO_MORE_ROWS if there are no more rows available. Procedures with no keys return all rows in the table on the first call, regardless of the value of the max_rpc_return_recs field.

6.6.1 Linked List Example

Data from list calls is returned in a linked list. The example in this section uses the acmsmgmt_list_log_1 procedure to illustrate how linked list processing works.

The call to the acmsmgmt_list_log_1 procedure requires the following input structure:

struct  log_sel_struct { 
    int          client_id; 
    string       before_time<TIME_SIZE_A>; 
    string       since_time<TIME_SIZE_A>; 
    string       file_name<STORAGE_LOC_SIZE>; 
    int          dup_count; 
    int          facility; 
    int          severity;     

In the code example that follows, the lines of code beginning with log_rec initialize the fields in this structure as follows:

The following example code shows the initialization of the client and the call to the acmsmgmt_list_log_1 procedure:

#include <rpc/rpc.h> 
#include <stdio.h> 
#include string 
#include "acmsmgmt_rpc.h" 
CLIENT *cl; 
int main () 
int skip_rec = 0; 
char null_time_str[24] = ""; 
char first_of_jan[24] = "01-JAN-1998 00:00:00.00"; 
char file_spec[] = ""; /* use default, i.e. active log file */ 
char time_cache[MGMT_S_TIME_A+1]; 
static struct  log_sel_struct log_rec; 
log_data_list  *log; 
log_link  *nl; 
/* Initialize client connection; if that fails, exit*/ 
cl = clnt_create(sname, ACMSMGMT_RPC, ACMSMGMT_VERSION, "tcp"); 
if (!cl) 
/* Create a default security context */ 
cl->cl_auth = authunix_create_default(); 
/* So far so good. Initialize log selection data */ 
log_rec.client_id   = 0; 
log_rec.before_time = null_time_str; 
log_rec.since_time  = first_of_jan; 
log_rec.file_name   = file_spec; 
log_rec.dup_count   = -1; 
log_rec.facility    = -1; /* don't match on facility */ 
log_rec.severity    = -1; /* don't match on severity */ 
/* Now make RPC */ 
log = acmsmgmt_list_log_1(&log_rec,cl); 

The return value from the calls to all list procedures (including acmsmgmt_list_log_1) is a pointer to a union. If the pointer returned is NULL, the call has failed. RPC error checking must be used to determine the cause of the error. If a valid pointer has been returned, it will point to a structure containing a union with the following structure:

struct log_data_list { 
        int status; 
        union { 
                log_list list; 
                int rc; 
        } log_data_list_u; 

The status field determines which structure is being returned. If the status is equal to MGMT_FAIL, the rc field is returned. The rc field contains a status code indicating the reason for failure.

If the status field is not equal to MGMT_FAIL, a pointer to a linked list has been returned.

The log_list field is defined as a pointer to linked list node, as follows:

typedef struct log_link *log_list; 

The linked list node has the following structure:

struct log_link { 
        logging_rec log_data; 
        log_list pNext; 

In this structure, log_data is of type logging_rec, which is a record structure containing the log data. The pNext field is a pointer to the next node in the linked list (which is of type log_link).

Figure 6-3 illustrates the return structure and how the linked list is constructed.

Figure 6-3 Linked List: Return Structure and Construction

The following example code shows how to check whether the call completed successfully, and how to traverse the linked list to display the data:

/* if a NULL pointer was returned, the RPC failed */ 
if (!log) 
/* if bad status was returned, something failed in our call. 
        log->log_data_list_u.rc contains the status */ 
if (log->status == MGMT_FAIL) 
/* while more data in the list, display the data */ 
for (nl = log->log_data_list_u.list; nl != NULL; nl = nl->pNext) { 
        if (skip_rec) 
                skip_rec = 0; 
                printf("\n %-12s\t%-s",sname,nl->log_data.log_msg); 
        /* save last time received to use as next time to read forward from */ 
        log_rec.dup_count  = nl->log_data.dup_count; 
        log_rec.since_time = time_cache; 
if (log->status == MGMT_NOMORE_DATA) 
        printf("\n *** End of data **"); 
else { 
        skip_rec = 1; 
        goto top; 

In this example, the returned pointer is checked for whether data has been returned (log is not NULL). Then the status code is checked for whether the call completed successfully.

If the call completed successfully, the code drops into a FOR loop and starts printing the data. For this particular call, the client prints all the records the very first time the RPC is called; on subsequent calls, the first record is a duplicate of the last one from the previous call and is not printed.

After printing a record, the key data is saved to be used again on a subsequent call. Remember that only max_rpc_return_recs is returned in each call to the acmsmgmt_list_log_data_1 procedure. There may be more log records than can be sent at once. It is the responsibility of the client to initialize the call properly to get the next set of records.

Once all the returned records have been returned, the code will call the acmsmgmt_list_log_data_1 procedure again if the status code from the call was not MGMT_NOMORE_DATA. In this way, all the records are retrieved.

Previous Next Contents Index