Skip Navigation Links | |
Exit Print View | |
ONC+ Developer's Guide Oracle Solaris 11 Express 11/10 |
1. Introduction to ONC+ Technologies
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
B. RPC Protocol and Language Specification
F. Writing a Port Monitor With the Service Access Facility (SAF)
Restricting Access to the System
Port Monitor Process IDs and Lock Files
Changing the Service Environment: Running doconfig()
Port Monitor Administrative File
Per-Service Configuration Files
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
Configuration Files and Scripts
Interpreting Configuration Scripts With doconfig()
Per-Port Monitor Configuration Files
Per-Service Configuration Files
Printing, Installing, and Replacing Configuration Scripts
Per-System Configuration Scripts
Per-Port Monitor Configuration Scripts
Per-Service Configuration Scripts
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 */