C H A P T E R  3

Building CLM Applications

For information about how to build applications that use the CLM API, see the following sections:

Installing Applications on a Cluster

If your application is to be run on a master-eligible or dataless node, install the application binary files on the node.

If your application is to be run on a diskless node, install the binaries on the master node in:


where diskless_node_name is the name of the diskless node and path is the path to the application. For example, if the binaries are installed in the /opt/mySvc/bin/myapp directory, the application binaries are installed in the /export/root/NetraDiskless1/opt/mySvc/bin/myapp directory for the NetraDiskless1 diskless node.

If your application will run on a dataless node, binaries can be installed on the local disk (as in the master-eligible node case) or on the shared partition (as in the diskless node case). It is recommended that they be installed on the local disk.

For definitions of the terms diskfull, diskless, and dataless nodes, see Cluster Model in the Netra High Availability Suite 3.0 1/08 Foundation Services Overview.

Setting Up a Makefile

To enable the compiler and linker to locate the required header files and libraries, specify the following entries in your makefile:

For the Solaris OS:

CFLAGS  += -I/opt/SUNWcgha/include/safLDFLAGS += -L/opt/SUNWcgha/lib \           -R/opt/SUNWcgha/lib           -lSaClm

Building a 32-bit application for use with the the Linux OS:

CFLAGS  += -I/opt/SUNWcgha/include/safLDFLAGS += -L/opt/SUNWcgha/lib \           -lSaClm

Building a 64-bit application for use with the the Linux OS:

CFLAGS  += -I/opt/SUNWcgha/include/safLDFLAGS += -L/opt/SUNWcgha/lib \           -lSaClm

Note - These entries apply only if the developer package header files and libraries are installed in their default locations. For information on installing the header files and libraries required by developers, see Installing Libraries and Header Files.

For an example makefile that uses a specified code example, see EXAMPLE 3-4.

Compiling Applications

The applications you develop using the CLM API can be compiled using the Sun Studio 10 software compiler. For more information, refer to the documentation that is supplied with Sun Studio software.

Including Applications in a Startup Script

Applications that are to run on a deployed Foundation Services cluster can be started automatically when the node is booted. For this, you can supply a startup script for the application. The startup script should be located in the /etc/init.d/ directory. Link the script to an entry in either the /etc/rc2.d/ directory or the /etc/rc3.d/ directory, and the script will be executed when the node boots. For more information, see the init1M (Solaris) or init8 (Linux) man page.

If you require fast performance from a program, ensure that shared objects linked with the program are loaded in memory at runtime. To load shared objects in memory at runtime, set the LD_BIND_NOW environment variable. For more information on this variable, see the Solaris OS documentation on Runtime Linker in the Linker and Libraries Guide, or for the Linux OS, refer to the ld (1) man page.

For better performance from programs running on diskless nodes in a test cluster, you can set the mlockall function within your program to lock address space. For more information, see the mlockall3C man page.

Running Your Applications on the Cluster

Applications that you develop on your development host can be tested on a cluster. For information about supported cluster configurations and how to connect your development host to a cluster, see the Netra High Availability Suite 3.0 1/08 Foundation Services Getting Started Guide.

To transfer applications from your development host to a cluster, use one of the following commands:

ftp The ftp command is the user interface to the Internet standard File Transfer Protocol. For more information, see the ftp1 man page.
rcp The rcp command is used to copy files between machines. For more information, see the rcp1 man page.
mount The mount command is used to mount file systems and remote resources. For more information, see the mount1M (Solaris) or (Linux) mount8man page.

Application Examples

The code fragment shown in EXAMPLE 3-1 enables the API to display peer node membership. This code fragment should be included when you run the CLM API examples provided in this guide. This code fragment includes saClmClusterNodeGet functions, which are explained in the following chapter.

EXAMPLE 3-1   Mandatory Code Fragment: common.c  
void print_node(const SaClmClusterNodeT *node)
    printf("Node %u\n"
        "Id:       %i\n"
        "Address: IPv%c %*.*s\n"
        "Name:     %*.*s\n"
        "Member:   %s\n"
        "Boot TS: %lli\n\n",
        (node->nodeAddress.family == SA_CLM_AF_INET ? '4' : '6'),
        node->nodeName.length, node->nodeName.length,
        (node->member ? "Yes" : "No"),

The code fragment in EXAMPLE 3-1 is accompanied by a common.h header file. The code in the common.h header file is used in many of the code samples in this guide and is shown in EXAMPLE 3-2.

EXAMPLE 3-2   The common.h Header File 
#ifndef __CLM_COMMON__
#define __CLM_COMMON__
#include <saClm.h>
* Required version
#define VERSION_RELEASE    'B'
#define VERSION_MAJOR     2
#define VERSION_MINOR     1
const char *changeString(SaClmClusterChangesT change);
const char *errString(SaAisErrorT code);
void print_node(const SaClmClusterNodeT *node);
void print_notification(const SaClmClusterNotificationT *notif);
void print_notif_buffer(const SaClmClusterNotificationBufferT *notif);

For instructions on installing header files, see Installing Libraries and Header Files.

To check that your development host and cluster are running correctly and that you are able to compile and run code using the CLM API, an example, NodeGet.c, is provided. This example uses:

This worked example is shown in EXAMPLE 3-3.

EXAMPLE 3-3   Example NodeGet.c Program  
#include <stdio.h>
#include <stdlib.h>
#include <saClm.h>
#include "common.h"
int main(void)
    SaClmHandleT          clmHandle;
    SaClmClusterNodeT     clusterNode;
    SaAisErrorT           res; 
    SaVersionT            version;
    version.releaseCode  = VERSION_RELEASE;
    version.majorVersion = VERSION_MAJOR;
    version.minorVersion = VERSION_MINOR;
    res = saClmInitialize(&clmHandle, NULL, &version);
    if (res != SA_AIS_OK) {
           printf("Failed to initialize the library: %s\n",
    saClmClusterNodeGet(clmHandle, SA_CLM_LOCAL_NODE_ID,
                        SA_TIME_MAX, &clusterNode);
    if (res != SA_AIS_OK) {
        printf("Failed to get node information: %s\n",                 errString(res));
               (void) saClmFinalize(clmHandle);
    return 0;

The function errString() does not belong to the CLM API and can be found in the common.c example file.

An example makefile is also provided in this section. This example makefile enables you to compile the NodeGet.c code in EXAMPLE 3-3, using:

This example makefile is shown in EXAMPLE 3-4.

EXAMPLE 3-4   Makefile for the NodeGet.c Program
CFLAGS += -I/opt/SUNWcgha/include/saf
LDLIBS += -L/opt/SUNWcgha/lib -lSaClm
all: $(PRG)
$(PRG): NodeGet.o common.o
        $(CC) $(LDLIBS) -o $@ NodeGet.o common.o
common.o: common.c common.h
NodeGet.o: NodeGet.c common.h
        $(CC) $(CFLAGS) -c $<

Note - The preceding example is for the Solaris OS. If your system uses the Linux OS, modify the makefile as described in Setting Up a Makefile.

For information about setting up a makefile, see Setting Up a Makefile.

The Foundation Services is supplied with source code examples in the SUNWnhsafclm developer package. These examples are installed in subdirectories of the /opt/SUNWcgha/examples/SaClm_API directory for Solaris-based systems, and in the /opt/sun/nhas/examples/SaClm_API directory for Linux-based systems.

Library Life Cycle

Before using the library, the application must initialize it by calling the saClmInitialize() function. This function takes two input arguments. The first argument is a pair of callback functions to be associated with the receipt of notifications and receipt of results from asynchronous API calls. The other argument is the library version requested. If the bound library is incompatible with the requested version, the call will fail.On return, the function returns a handle to be used in any subsequent calls to the library. For more information, refer to the saClmInitialize (3clm) man page.The application must obtain the selection object associated with the handle using the function saClmSelectionObjectGet(). Any thread tracking changes or expecting responses from asynchronous calls must wait for this selection object (a file descriptor). You can use select(3C) or poll(2) to wait for the data. When the data is available, use the saClmDispatch() function to process the pending callbacks.When the library will no longer be used, call the function saClmFinalize() to destroy the handle and free the allocated resources.Multiple initializations of the library are possible. Each initialization will have its own handle, and a full life cycle must be implemented for each.