JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
ONC+ Developer's Guide     Oracle Solaris 11 Express 11/10
search filter icon
search icon

Document Information

Preface

1.  Introduction to ONC+ Technologies

2.  Introduction to TI-RPC

3.  rpcgen Programming Guide

4.  Programmer's Interface to RPC

5.  Advanced RPC Programming Techniques

6.  Porting From TS-RPC to TI-RPC

7.  Multithreaded RPC Programming

8.  Extensions to the Sun RPC Library

9.  NIS+ Programming Guide

A.  XDR Technical Note

B.  RPC Protocol and Language Specification

C.  XDR Protocol Specification

D.  RPC Code Examples

E.  portmap Utility

F.  Writing a Port Monitor With the Service Access Facility (SAF)

What Is the SAF?

What Is the SAC?

Basic Port Monitor Functions

Port Management

Activity Monitoring

Other Port Monitor Functions

Restricting Access to the System

Creating utmpx Entries

Port Monitor Process IDs and Lock Files

Changing the Service Environment: Running doconfig()

Terminating a Port Monitor

SAF Files

Port Monitor Administrative File

Per-Service Configuration Files

Private Port Monitor Files

SAC/Port Monitor Interface

Message Formats

SAC Messages

Port Monitor Messages

Message Classes

Port Monitor Administrative Interface

SAC Administrative File _sactab

Port Monitor Administrative File _pmtab

SAC Administrative Command sacadm

Port Monitor Administrative Command pmadm

Monitor-Specific Administrative Command

Port Monitor/Service Interface

New Service Invocations

Standing Service Invocations

Port Monitor Requirements

Initial Environment

Important Files

Port Monitor Responsibilities

Configuration Files and Scripts

Interpreting Configuration Scripts With doconfig()

Per-System Configuration File

Per-Port Monitor Configuration Files

Per-Service Configuration Files

Configuration Language

assign Keyword

push Keyword

pop Keyword

runwait Keyword

run Keyword

Printing, Installing, and Replacing Configuration Scripts

Per-System Configuration Scripts

Per-Port Monitor Configuration Scripts

Per-Service Configuration Scripts

Sample Port Monitor Code

Logic Diagram and Directory Structure

Glossary

Index

Sample Port Monitor Code

The following code example is a “null” port monitor that simply responds to messages from the SAC.

Example F-1 Sample Port Monitor

# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>
# include <fcntl.h>
# include <signal.h>
# include <sac.h>

char Scratch[BUFSIZ]; /* scratch buffer */
char Tag[PMTAGSIZE + 1]; /* port monitor's tag */
FILE *Fp; /* file pointer for log file */
FILE *Tfp; /* file pointer for pid file */
char State; /* port monitor's current state*/

main(argc, argv)
    int argc;
    char *argv[];
{
    char *istate;
    strcpy(Tag, getenv("PMTAG"));
/*
 * open up a log file in port monitor's private directory
 */
    sprintf(Scratch, "/var/saf/%s/log", Tag);
    Fp = fopen(Scratch, "a+");
    if (Fp == (FILE *)NULL)
        exit(1);
    log(Fp, "starting");
/*
 * retrieve initial state (either "enabled" or "disabled") and set
 * State accordingly
 */
    istate = getenv("ISTATE");
    sprintf(Scratch, "ISTATE is %s", istate);
    log(Fp, Scratch);
    if (!strcmp(istate, "enabled"))
        State = PM_ENABLED;
    else if (!strcmp(istate, "disabled"))
        State = PM_DISABLED;
    else {
        log(Fp, "invalid initial state");
        exit(1);
    }
    sprintf(Scratch, "PMTAG is %s", Tag);
    log(Fp, Scratch);
/*
 * set up pid file and lock it to indicate that we are active
 */
    Tfp = fopen("_pid", "w");
    if (Tfp == (FILE *)NULL) {
        log(Fp, "couldn't open pid file");
        exit(1);
    }
    if (lockf(fileno(Tfp), F_TEST, 0) < 0) {
        log(Fp, "pid file already locked");
        exit(1);
    }
    fprintf(Tfp, "%d", getpid());
    fflush(Tfp);
    log(Fp, "locking file");
    if (lockf(fileno(Tfp), F_LOCK, 0) < 0) {
        log(Fp, "lock failed");
        exit(1);
    }
/*
 * handle poll messages from the sac ... this function never
returns
 */
    handlepoll();
    pause();
    fclose(Tfp);
    fclose(Fp);
}

handlepoll()
{
    int pfd; /* file descriptor for incoming pipe */
    int sfd; /* file descriptor for outgoing pipe */
    struct sacmsg sacmsg; /* incoming message */
    struct pmmsg pmmsg; /* outgoing message */
/*
 * open pipe for incoming messages from the sac
 */
    pfd = open("_pmpipe", O_RDONLY|O_NONBLOCK);
    if (pfd < 0) {
        log(Fp, "_pmpipe open failed");
        exit(1);
    }
/*
 * open pipe for outgoing messages to the sac
 */
    sfd = open("../_sacpipe", O_WRONLY);
    if (sfd < 0) {
        log(Fp, "_sacpipe open failed");
        exit(1);
    }
/*
 * start to build a return message; we only support class 1
messages
 */
    strcpy(pmmsg.pm_tag, Tag);
    pmmsg.pm_size = 0;
    pmmsg.pm_maxclass = 1;
/*
 * keep responding to messages from the sac
 */
     for (;;) {
         if (read(pfd, &sacmsg, sizeof(sacmsg)) != sizeof(sacmsg)) {
             log(Fp, "_pmpipe read failed");
             exit(1);
         }
/*
 * determine the message type and respond appropriately
 */
         switch (sacmsg.sc_type) {
             case SC_STATUS:
                 log(Fp, "Got SC_STATUS message");
                 pmmsg.pm_type = PM_STATUS;
                 pmmsg.pm_state = State;
                 break;
             case SC_ENABLE:
                 /*note internal state change below*/
                 log(Fp, "Got SC_ENABLE message");
                 pmmsg.pm_type = PM_STATUS;
                 State = PM_ENABLED;
                 pmmsg.pm_state = State;
                 break;
             case SC_DISABLE:
                 /*noteinternalstatechangebelow*/
                 log(Fp, "Got SC_DISABLE message");
                 pmmsg.pm_type = PM_STATUS;
                 State = PM_DISABLED;
                 pmmsg.pm_state = State;
                 break;
             case SC_READDB:
                 /*
                 * If this were a fully functional port
                                 * monitor, it would read _pmtab here and
                                 * take appropriate action
                 */
                 log(Fp, "Got SC_READDB message");
                 pmmsg.pm_type = PM_STATUS;
                 pmmsg.pm_state = State;
                 break;
             default:
                 sprintf(Scratch, "Got unknown message <%d>",
                 sacmsg.sc_type);
                 log(Fp, Scratch);
                 pmmsg.pm_type = PM_UNKNOWN;
                 pmmsg.pm_state = State;
                 break;
         }
/*
 * send back a response to the poll
 * indicating current state
 */
         if (write(sfd, &pmmsg, sizeof(pmmsg)) != sizeof(pmmsg))
             log(Fp, "sanity response failed");
     }
}
/*
 * general logging function
 */
log(fp, msg)
    FILE *fp;
    char *msg;
{
    fprintf(fp, "%d; %s\n", getpid(), msg);
    fflush(fp);
}

The following code example shows the sac.h header file.

Example F-2 sac.h Header File

/* length in bytes of a utmpx id */
# define IDLEN 4          /* wild character for utmpx ids */
# define SC_WILDC 0xff    /* max len in bytes for port monitor tag */
# define PMTAGSIZE 14

/* values for rflag in doconfig() */

# define NOASSIGN 0x1     /* don't allow assign operations */
# define NORUN 0x2        /* don't allow run or runwait operations */
/*
 * Message to SAC (header only). This header is forever fixed.
 * The size field (pm_size) defines the size of the data portion of the
 * message, which follows the header. The form of this optional data
 * portion is defined strictly by the message type (pm_type).
 */
struct pmmsg {
    char pm_type;         /* type of message */
    unchar pm_state;      /* current state of pm */
    char pm_maxclass;     /* max message class this port monitor understands */
    char pm_tag[PMTAGSIZE + 1];    /* pm's tag */
    int pm_size;          /* size of opt data portion */
};

/* pm_type values */

# define PM_STATUS 1      /* status response */
# define PM_UNKNOWN 2     /* unknown message was received */

/* pm_state values */

/* Class 1 responses */
# define PM_STARTING 1    /* monitor in starting state */
# define PM_ENABLED 2     /* monitor in enabled state */
# define PM_DISABLED 3    /* monitor in disabled state */
# define PM_STOPPING 4    /* monitor in stopping state */

/* Message to port monitor */
struct sacmsg {
    int sc_size;          /* size of optional data portion */
    char sc_type;         /* type of message */
};

/* sc_type values
 * These represent commands that the SAC sends to a port monitor. These
 * commands are divided into "classes" for extensibility. Each subsequent
 * "class" is a superset of the previous "classes" plus the new commands
 * defined within that "class". The header for all commands is identical.
 * However, a command may be defined such that an optional data portion
 * may be sent in addition to the header. The format of this optional data
 * piece is self-defining based on the command.
 * Important note: The first message sent by the SAC must always be a
 * class 1 message. The port monitor response indicates the maximum class
 * that it is able to understand. Also port monitors should only respond to
 * a message with an equivalent class response (i.e. a class 1 command causes
 * a class 1 * response).
 */

/* Class 1 commands (currently, there are only class 1 commands) */
# define SC_STATUS 1      /* status request */
# define SC_ENABLE 2      /* enable request */
# define SC_DISABLE 3     /* disable request */
# define SC_READDB 4      /* read pmtab request */
/*
 * `errno' values for Saferrno. Note that Saferrno is used by both
 * pmadm and sacadm and these values are shared between them
 */
# define E_BADARGS 1      /* bad args/ill-formed cmd line */
# define E_NOPRIV 2       /* user not priv for operation */
# define E_SAFERR 3       /* generic SAF error */
# define E_SYSERR 4       /* system error */
# define E_NOEXIST 5      /* invalid specification */
# define E_DUP 6          /* entry already exists */
# define E_PMRUN 7        /* port monitor is running */
# define E_PMNOTRUN 8     /* port monitor is not running */
# define E_RECOVER 9      /* in recovery */