Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

swlist(1)

bootpd(1M)

dcnodes(1M)

dcnodesd(1M)

inetd(1M)

gethostname(2)

setrlimit(2)

setuid(2)

gethostent(3N)

fdopen(3S)

malloc(3C)

rcmd(3N)

dcnodes(3X)

NAME

dcnodes(), dcnodes_status(), dcnodes_status_string(), dcnodes_error_string(), dcnodes_server_ipaddr(), enddcnodes() − report on diskless cluster nodes

SYNOPSIS

#include <dcnodes.h>

int dcnodes (

const int mode,
struct dcnode **dcnode

);

int dcnodes_status (

const int mode,
struct dcnode *dcnode,
const int num_dcnodes,
const time_t timeout

);

int dcnodes_status_string (

const int mode,
const int statval

);

int dcnodes_error_string (const int retval);

int dcnodes_server_ipaddr (

char *ipaddr,
const int len

);

unsigned long dcnodes_mtime (void);

void enddcnodes (void);

Remarks

These functions reside in libdc.a, and are linked using the -ldc option to the ld or cc command. 

DESCRIPTION

These functions help a program get static (configuration) and dynamic (status) information about diskless cluster nodes (server, and clients).  The dcnodes() and dcnodes_status() functions return information about all nodes in a cluster (including the cluster server), when run on any node in the cluster.  The dcnodes_server_ipaddr() function returns the internet address of a cluster client’s server system. 

The dcnode structure is defined in <dcnodes.h> and includes at least the following members.  Each string is null-terminated. 

char dcn_name[]; /* node name; see below */
char dcn_ipaddr[]; /* IP address, dot form */
char dcn_hwaddr[]; /* hardware address, hex form */
char dcn_netmask[]; /* net/subnet mask, dot form */
char dcn_route[]; /* default route, dot form */
char dcn_shroot[]; /* OS shared root description */
int dcn_status; /* system status; see below */

The file also defines the following constants and data types:

DCNODES_SHORT /* mode parameter to dcnodes(); see below */
DCNODES_LONG

DCNODES_LONGER

DCNODES_ALL

DCNODES_TYPE

DCNODES_STATUS /* mode parameter to dcnodes_status() */
DCNODES_STATUS_DETAILS

These lengths do not include the null terminator:

DCN_NAME_LEN /* maximum dcnode name length */
DCN_IPADDR_LEN /* maximum IP address length */
DCN_HWADDR_LEN /* maximum HW address length */
DCN_NETMASK_LEN /* maximum net/subnet mask length */
DCN_ROUTE_LEN /* maximum default route length */
DCN_SHROOT_LEN /* maximum OS shared root length */
DCN_STATUS_LEN /* size of status value (int) */



DCN_VALUE_UNKNOWN /* field value cannot be determined */



DCN_TYPE_STANDALONE /* results of DCNODES_TYPE */
DCN_TYPE_SERVER

DCN_TYPE_CLIENT




DCN_ERR_MEMORY /* error return codes; see below */
DCN_ERR_IPADDR

DCN_ERR_RCMD

DCN_ERR_FDOPEN

DCN_ERR_STARTUP

DCN_ERR_VERSION

DCN_ERR_EXEC

DCN_ERR_READ

DCN_ERR_SOCKET

DCN_ERR_CONNECT




DCN_STATUS_UNKNOWN /* status values; see below */
DCN_STATUS_STANDALONE

DCN_STATUS_SERVER

DCN_STATUS_ACTIVE

DCN_STATUS_INACTIVE

DCN_STATUS_NO_IP_ADDR

DCN_STATUS_NO_DATA




DCN_IS_UP(status) /* macros for checking status value */
DCN_IS_SERVER(status)

DCN_IS_CLIENT(status)

DCN_IS_LOCAL_ROOT(status)

typedef struct dcnode *dcnp_t;

#define DCN_NULLP ((dcnp_t) 0)
#define DCN_NULLPP ((dcnp_t *) 0)
#define DCN_SIZE (sizeof (struct dcnode))


#define DCN_PROG_NULLP ((void (*)()) 0)

If invoked on a cluster client (remote-root) node, dcnodes() and dcnodes_status() contact the node’s root server system to obtain information about all of the cluster’s nodes, except as noted below.  This requires rcmd() access from the client to the server by the effective user ID of the calling process (see rcmd(3N) and setuid(2)) to execute the dcnodes command. 

The functions have the following purposes:

dcnodes() This function modifies the dcnode pointer to point to an array of dcnode structures, each containing information for one node, and returns the number of nodes in the list.  The cluster server is always the first system in the list.  The mode parameter determines which operation is performed:

DCNODES_SHORT
Return a count, and a list, of cluster node names; other structure fields are undefined (except dcn_ipaddr, which is set to null for convenience in calling dcnodes_status()).  The cluster server’s dcn_name value is its domain-expanded hostname value (see gethostname(2)), that is, the result of looking up the system’s hostname in the hosts database using gethostbyname() (see gethostent(3N)). Cluster clients’ dcn_name values are their names as listed in the cluster client list on the server (see FILES below), normally including domain parts, which should but might not match each client’s hostname and uname.nodename values. 

With DCNODES_SHORT, the dcnode parameter can be a null pointer, which causes dcnodes not to allocate space for, and build the list of, cluster node names.  In this case it only returns a count of cluster nodes. 

An unrecognized mode value is treated as DCNODES_SHORT. 

DCNODES_LONG Fill in all structure fields except dcn_shroot and dcn_status.  dcn_shroot is undefined.  dcn_status is set to one of the following as appropriate:

DCN_STATUS_UNKNOWN for cluster clients (default value)

DCN_STATUS_SERVER for cluster server systems

DCN_STATUS_STANDALONE
for standalone systems

The dcn_status field can be filled in by calling dcnodes_status() as described below.  If dcnodes() cannot determine the value for any field, that field is set to the value of the DCN_VALUE_UNKNOWN macro. 

If a standalone or cluster server system has multiple LAN interface cards, there is an entry for each card in the returned array.  Each of those entries contains the same values for dcn_route and dcn_status, but different values for dcn_ipaddr and dcn_hwaddr.  The values for dcn_name and dcn_netmask might differ, reflecting each of the server’s LAN interface cards.  If a LAN interface card is down, its dcn_ipaddr value is “(card down)”. 

If the system on which dcnodes() is invoked is standalone and has no LAN cards, a single entry is returned with dcn_name set to the host’s domain-expanded hostname value, and dcn_ipaddr, dcn_hwaddr, and dcn_netmask set to the value of DCN_VALUE_UNKNOWN. 

DCNODES_LONGER
Same as DCNODES_LONG except also fill in the dcn_shroot field.  This can take significant extra time.  The cluster server’s dcn_shroot value is always “/”; client values are truncated if necessary, and always null-terminated.  If any client’s OS shared root description is null, its path appears instead. 

DCNODES_ALL Fill in the array just as for DCNODES_LONGER, and then call dcnodes_status() with a mode of DCNODES_STATUS and a timeout value of 10 seconds to also fill in dcn_status fields (for all clients) before returning.  This saves the caller from calling dcnodes_status() separately. 

DCNODES_TYPE Ignore the dcnode parameter and just return DCN_TYPE_SERVER if the system is a cluster server, DCN_TYPE_CLIENT if it is a cluster client, or DCN_TYPE_STANDALONE if it is a standalone system (it has a local root and no remote-root clients are configured).  When dcnodes() is called on a remote-root client with this mode it does not contact the cluster server. 

The returned array exists in static space (malloc’d memory — see malloc(3C)). This memory is overwritten by the next call, so previously returned pointers become invalid after the next call.

dcnodes_status()
Using an array of dcnode structures containing one or more elements, dcnodes_status() obtains information on the status of each node from the dcnodes status daemon ( dcnodesd ).  Information from the daemon is matched with a dcnode array entry by dcnodes_status() uses the dcn_ipaddr field in each dcnode structure if it is non-null, and not equal to the value DCN_VALUE_UNKNOWN; otherwise, it uses the dcn_name field in the dcnodes structure.  dcnodes_status() then fills in the dcn_status field for each node’s element.  See “Status Fields” below for a description of possible field values. 

Pass the function a mode (mode) value which is either DCNODES_STATUS or DCNODES_STATUS_DETAILS, a count (num_dcnodes) of the number of nodes to process, and a pointer (dcnode) to the first element of the array. If any node’s IP address is not specified, it converts the node’s name to an IP address using gethostbyname() (see gethostent(3N)).

Also pass the function a timeout value in seconds.  This value is the number of seconds that must elapse between the time that a client sends a keepalive packet to the server and the time when the client is inactive.  By default, clients send keepalive packets every five seconds.  A 10 second timeout, then, means that any timestamp older than 10 seconds is considered invalid and the client is marked as inactive. 

dcnodes_status_string()
This function takes a mode value (DCNODES_SHORT or DCNODES_LONG) and a client status value (the dcn_status field, any of DCN_STATUS_*), and returns a constant or static string equivalent (changed or overwritten by the next call to this function or to catgets()), in either short or long form.  If the status value is DCN_STATUS_UNKNOWN or any unrecognized value, the returned string is the value of DCN_VALUE_UNKNOWN. 

dcnodes_error_string()
This function takes a return value from dcnodes() or dcnodes_status() and returns a constant or static string (changed or overwritten by the next call to this function or to catgets()), that describes the error condition, suitable for use in an error message.  The string begins with an uppercase letter but lacks a trailing period.  If the error condition has an errno value associated (see RETURN VALUE below), the global errno value is interpreted as part of the returned error message.  If the value passed to dcnodes_error_string() is unrecognized, it returns an appropriate message. 

dcnodes_server_ipaddr()
This function looks up the internet address part of the mount point for “/” and copies it to the caller’s ipaddr buffer.  The string is always null-terminated and truncated if necessary to fit.  The size of the buffer and the len value are normally DCN_IPADDR_LEN + 1. 

This function should only be called on a cluster client, that is, a remote-root system whose “/” directory is NFS-mounted.  The server’s IP address is derived from the mount point of “/” in the system mount table.  This function assumes the server ID is an IP address, not a name. 

dcnodes_mtime()
cwThis function allows an application to avoid calling dcnodes() again if it’s unnecessary to do so because the data hasn’t changed.  dcnodes_mtime() returns the latest mtime stamp on any file used by dcnodes() to return its data.  If none of the files exists, returns 0. 

This function can only be called on a cluster server. 

enddcnodes() Frees any malloc’d memory previously allocated by dcnodes().  (Do not call free() on a dcnode pointer previously passed to dcnodes(), because dcnodes() does this itself.)  Memory is only allocated by calls to dcnodes() with DCNODES_LONG, DCNODES_LONGER, DCNODES_ALL, or DCNODES_SHORT with a non-null dcnode pointer. 

Note that a system with a local root directory (root volume) is considered to be standalone or a cluster server as appropriate, not a cluster client, even if most of its files are NFS-mounted from other systems. 

Status Fields

The dcn_status field for each node is set to one of the following values (defined in dcnodes.h) by dcnodes_status() when it is called using a mode parameter of DCNODES_STATUS:

DCN_STATUS_UNKNOWN Default value from dcnodes(); also used if the node name and IP address passed to dcnodes_status() are both null or equal to the value of DCN_VALUE_UNKNOWN. 

DCN_STATUS_STANDALONE
System on which dcnodes_status() was invoked is up with a local root volume and has no remote-root clients configured. 

DCN_STATUS_SERVER Cluster (root) server, which is necessarily “up”. 

DCN_STATUS_ACTIVE Node is up as a remote-root client of the local cluster.  It allows rcmd() from the cluster (root) server and identifies that system as its root server.  Note that all nodes in a cluster are normally configured to allow rcmd() access, at least to privileged users, between the cluster server and clients. 

DCN_STATUS_INACTIVE
Node has an unknown name (cannot look up internet address), does not respond to or does not allow rcmd() from the cluster (root) server, is up standalone (local-rooted), or is booted on another root server.  A node is marked inactive if anything goes wrong, including timeout, while trying to check that is it active. 

If the mode parameter is DCNODES_STATUS_DETAILS, instead of marking a client with DCN_STATUS_INACTIVE its status value is one of the following:

DCN_STATUS_NO_IP_ADDR
A dcn_name value was provided, dcn_ipaddr was not, and the given client name is unknown to the hosts database (cannot be mapped to an IP address). 

DCN_STATUS_NO_DATA The dcnodesd daemon could not be contacted, or had no data for the specified client. 

EXTERNAL INFLUENCES

Environment Variables

LANG specifies the language used to return messages from dcnodes_status_string() and dcnodes_error_string(). 

If LANG is not specified or is set to the empty string, a default of “C” (see lang(5)) is used instead of LANG.  If any internationalization variable contains an invalid setting, the string functions behave as if all internationalization variables are set to “C”.  See environ(5).

RETURN VALUE

Upon successful completion, dcnodes() and dcnodes_status() return the number of array elements in the list.  This value is 1 or greater, except if dcnodes_status() is called with num_dcnodes less than 1, it returns 0, and if it is called on a cluster client with more than about 10Kb worth of node names, it returns the number of array elements for which status was set (see WARNINGS below). 

If dcnodes() is called with DCNODES_SHORT, the number of array elements is the number of cluster nodes; with DCNODES_LONG, DCNODES_LONGER, or DCNODES_ALL, there are more elements than dcnodes if the server has multiple LAN cards; with DCNODES_TYPE, the return value is DCN_TYPE_STANDALONE (standalone system), DCN_TYPE_SERVER (cluster server), or DCN_TYPE_CLIENT (cluster client). 

In case of error, dcnodes() and dcnodes_status() return a negative value, and do not alter the dcnode parameter. 

DCN_ERR_MEMORY Cannot allocate memory to hold the returned array (for dcnodes()) or an internal array (for dcnodes_status()); errno is set. 

The following errors are returned if called on a cluster client when there is difficulty contacting, and reading information from, the client’s cluster (root) server. 

DCN_ERR_IPADDR Cannot determine the server’s IP address from the “/” mount point. 

DCN_ERR_RCMD Cannot call rcmd() to get information from the server.  Problems include failure to find service “shell” of type “tcp” in the services database, or the effective user’s name in the accounts database. 

DCN_ERR_FDOPEN Cannot map file descriptor to a stream using fdopen() (see fdopen(3S)); errno is set. 

DCN_ERR_STARTUP dcnodes command on the server did not return a data format version number.  The command might be missing or non-executable, or might have failed before issuing a version number. 

DCN_ERR_VERSION dcnodes command on the server did not return the expected data format version number.  The command is incompatible with the local version of the dcnodes() or dcnodes_status() function. 

DCN_ERR_EXEC dcnodes command on the server failed (returned -1) after issuing a correct data format version number.  The reason is unknown. 

DCN_ERR_READ dcnodes command on the server failed (returned wrong amount of data) after issuing a correct data format version number.  The reason is unknown.  In this case only, dcnodes_status() might have modified some of the dcn_status fields in the dcnode parameter (array). 

dcnodes_server_ipaddr() returns 0 if it sets ipaddr successfully.  It returns DCN_ERR_IPADDR, and ipaddr is unchanged, if it cannot find “/” in the system mount table, or if “/” is not NFS-mounted. 

EXAMPLES

The following code fragment obtains all but status information for all members of the cluster on which it is run, and then fills in basic status information for the first three clients (after the cluster server’s entries), or for as many clients as there are if there are fewer than three, with a timeout of 20 seconds. 


 #include <dcnodes.h>
 int    num_dcnodes; /* count of nodes   */
dcnp_t dcnp;        /* node information */
int    index;       /* in dcnp          */
 if ((num_dcnodes = dcnodes (DCNODES_LONG, & dcnp)) <= 0)
{
    (handle error)
    ... dcnodes_error_string (num_dcnodes) ...
}
 /* skip standalone/server entries: */
 for (index = 1; index < num_dcnodes; ++index)
    if (dcnp[index].dcn_status == DCN_STATUS_UNKNOWN))
        break;
 if (index < num_dcnodes)   /* have one or more clients */
{
    int num_clients = num_dcnodes - index;
     if (dcnodes_status (DCNODES_STATUS,
                        dcnp + index,
                        (num_clients < 3) ? num_clients : 3,
                        /* timeout = */ 20) < 0)
    {
        (handle error)
    }
     ... dcnodes_status_string (DCNODES_SHORT, dcnp -> dcn_status) ...
}

WARNINGS

These functions are unsafe in multi-thread applications. 

Using dcnodes() it is possible to distinguish between standalone, server, and client systems, and behave differently depending on the system type.  However, it is desirable that applications not make this distinction, and it is usually found to be unnecessary upon closer analysis. 

dcnodes() uses malloc() and free() to manage the memory for the array it returns.  If desired, save a copy of an old array in new memory before calling dcnodes() again with a non-null dcnode pointer.  Call enddcnodes(), not free(), to release the current array when it’s no longer needed. 

dcnodes_status() expects to be called only with cluster client names or IP addresses obtained via dcnodes().  It assumes each specified host is a cluster member.  It does not check for or distinguish non-members.  They appear to be inactive clients. 

On a cluster client dcnodes_status() does not build a command line (to run on the cluster server) with a length greater than 10 kilobytes.  It ignores (does not modify status field for) any additional clients whose names or IP addresses don’t fit, and returns the number of clients for which status was determined. 

Normally the cluster server system provides boot, root, and OS shared root services to all client nodes in its cluster.  If boot, root, and/or OS shared root services are provided by separate systems, dcnodes() and dcnodes_status() might return incomplete information, that is, field values of DCN_VALUE_UNKNOWN.  They consider the cluster clients of a root server system to be those appearing in the system’s list of configured cluster client nodes (see FILES below).  When invoked on a remote-root client, they return information about the cluster nodes listed for the client’s root server system, using information in files on that server system.  If any file is missing (or any error occurs trying to access it), dcnodes() and dcnodes_status() do not complain, but return incomplete data. 

The dcnodes() and dcnodes_status() functions call rcmd() to reach the cluster server when called on a cluster client.  To ensure success, dcnodes() and dcnodes_status() on a cluster client should only be invoked by programs running with appropriate privilege to use rcmd() to reach the cluster server.  Also, rcmd() writes messages to standard error in case of failure, and can cause log entries in the syslog files on the target systems if inetd is run with the -l option (see inetd(1M)).

Performance Issues

dcnodes_status() might run much faster if dcn_ipaddr is specified for each client (not just dcn_name), because it does not have to look up each client’s internet addresses in the hosts database (although this does allow dcnodes_status() to try all of the addresses, if necessary, to reach a client). 

If dcnodes_status() is invoked on a cluster client with just that system’s name in the dcnodes list, it still contacts the cluster server to determine that the system is active.  This is inefficient. 

AUTHOR

These functions were developed by HP. 

FILES

/etc/clients.dc list of configured cluster client nodes that receive root service from a system; blank and comment lines (starting with “#”) are allowed and ignored

/etc/bootptab control file for bootpd (see bootpd(1M)) that contains most of the client information returned by dcnodes()

SEE ALSO

swlist(1), bootpd(1M), dcnodes(1M), dcnodesd(1M), inetd(1M), gethostname(2), setrlimit(2), setuid(2), gethostent(3N), fdopen(3S), malloc(3C), rcmd(3N). 

Hewlett-Packard Company  —  HP-UX Release 10.20:  July 1996

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026