ARPDAS_QNX6 1.0
cic.c
Go to the documentation of this file.
00001 /* cic.c Defines functions used by Command Interpreter Clients */
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include <unistd.h>
00005 #include <errno.h>
00006 #include "nortlib.h"
00007 #include "tm.h"
00008 #include "cmdalgo.h"
00009 
00010 #define CMD_PREFIX_MAX 10
00011 #define CMD_VERSION_MAX 80
00012 static char cic_header[CMD_PREFIX_MAX] = "CIC";
00013 static char *cis_node;
00014 static int sent_quit = 0;
00015 static int cis_fd = -1;
00016 static int playback = 0;
00017 int cic_cmd_quit_fd = -1;
00018 /* cgc_forwarding is 'cmdgen client forwarding'. It is apparently
00019    only used when the local command server is a generic forwarder.
00020    This is supposed to address the ambiguity about who should quit
00021    when a quit or exit command is issued. In the forwarding case,
00022    cgc_forwarding is not cleared when a 'Quit' is issued, so although
00023    cmd_interact() will exit, we may not want the client to terminate.
00024    Instead, we clear cgc_forwarding explicitly on an 'Exit' command.
00025    That was the idea, anyway, but generic forwarding never got past
00026    the drawing board stage.
00027  */
00028 int cgc_forwarding = 0;
00029 
00030 void cic_options(int argcc, char **argvv, const char *def_prefix) {
00031   int c;
00032   extern char *opt_string;
00033 
00034   if (def_prefix != NULL) {
00035     strncpy( cic_header, def_prefix, CMD_PREFIX_MAX );
00036     cic_header[CMD_PREFIX_MAX-1] = '\0';
00037   }
00038   optind = OPTIND_RESET;
00039   opterr = 0;
00040   if (argcc > 0) do {
00041     c=getopt(argcc,argvv,opt_string);
00042     switch (c) {
00043       case 'C':
00044         cis_node = optarg;
00045         break;
00046       case 'p':
00047         playback = 1;
00048         break;
00049       case '?':
00050         nl_error(3, "Unknown option -%c", optopt);
00051       default:
00052         break;
00053     }
00054   } while (c!=-1);
00055   opterr = 1;
00056 }
00057 
00058 /* cic_init() Locates the Command Interpreter Server (CIS) using
00059    either the default node information or the information set
00060    by cic_options -C <node>. Once located, if ci_version is
00061    non-empty, the version is queried. cic_init() uses the
00062    standard nl_response codes to determine whether fatal
00063    response is required. Returns zero on success.
00064 */
00065 int cic_init(void) {
00066   int nlrsave;
00067   if (cis_fd != -1) return 0;
00068   nlrsave = set_response(playback ? NLRSP_QUIET : NLRSP_WARN);
00069   cic_cmd_quit_fd = tm_open_name( tm_dev_name( "cmd/Quit" ),
00070     cis_node, O_RDONLY|O_NONBLOCK );
00071   set_response(nlrsave);
00072   if (playback) return 0;
00073   cis_fd = tm_open_name( tm_dev_name( CMDSRVR_NAME ),
00074     cis_node, O_WRONLY );
00075   if (cis_fd < 0)
00076     return(1);
00077   
00078   /* If specified, verify version */
00079   if (ci_version[0] != '\0') {
00080     char vcheck[CMD_VERSION_MAX];
00081     int nb = snprintf( vcheck, CMD_VERSION_MAX, "[%s:V%s]\n",
00082       cic_header, ci_version );
00083     if ( nb >= CMD_VERSION_MAX )
00084       nl_error( nl_response, "Version string too long" );
00085     else {
00086       int rb = write( cis_fd, vcheck, nb+1 );
00087       if ( rb == -1 ) {
00088         if (errno == EINVAL ) {
00089           if (nl_response)
00090             nl_error(nl_response, "Incorrect Command Server Version");
00091         } else nl_error(nl_response,
00092            "Error %d querying command server version", errno );
00093         return(1);
00094       }
00095       if ( rb < nb+1 )
00096         nl_error( 1, "Vcheck rb = %d instead of %d", rb, nb+1 );
00097     }
00098   }
00099 
00100   return(0);
00101 }
00102 
00103 void cic_reset(void) {
00104   if ( cis_fd != -1 ) {
00105     close(cis_fd);
00106     cis_fd = -1;
00107   }
00108   if ( cic_cmd_quit_fd != -1 ) {
00109     close(cic_cmd_quit_fd);
00110     cic_cmd_quit_fd = -1;
00111   }
00112 }
00113 
00114 static long int ci_time = 0L;
00115 void ci_settime( long int time ) {
00116   ci_time = time;
00117 }
00118 
00119 const char *ci_time_str( void ) {
00120   static char buf[11];
00121   int hour, min, sec;
00122   long int time = ci_time;
00123 
00124   if ( ! playback || time == 0 ) return "";
00125   if ( time < 0 ) return "-1: ";
00126   time = time % ( 24 * 3600L );
00127   hour = time / 3600;
00128   time = time % 3600;
00129   min = time / 60;
00130   sec = time % 60;
00131   sprintf( buf, "%02d:%02d:%02d: ", hour, min, sec );
00132   return buf;
00133 }
00134 
00135 /* ci_sendcmd() Sends a command to the CIS.
00136    If cmdtext==NULL, sends CMDINTERP_QUIT,0
00137     mode == 0 ==> CMDINTERP_SEND
00138     mode == 1 ==> CMDINTERP_TEST
00139     mode == 2 ==> CMDINTERP_SEND_QUIET
00140    Possible errors:
00141      Unable to locate CIS: Normally fatal: return 1
00142      CMDREP_QUIT from CIS: Reset cis_fd: return it
00143      CMDREP_SYNERR from CIS: Normally error: return it
00144      CMDREP_EXECERR from CIS: Normally warning: return it
00145 */
00146 int ci_sendcmd(const char *cmdtext, int mode) {
00147   char *cmdopts = "";
00148   int clen, rv;
00149   char buf[CMD_MAX_COMMAND_IN+1];
00150   
00151   if (sent_quit) return(1);
00152   if (!playback && cis_fd < 0 && cic_init() != 0) return(1);
00153   if (cmdtext == NULL) {
00154     cmdopts = ":X";
00155     cmdtext = "";
00156     nl_error(-3, "Sending Quit to Server");
00157   } else {
00158     switch (mode) {
00159       case 1: cmdopts = ":T"; break;
00160       case 2: cmdopts = ":Q"; break;
00161       default: break;
00162     }
00163     clen = strlen(cmdtext);
00164     { int len = clen;
00165       const char *ts = ci_time_str();
00166 
00167       if (len > 0 && cmdtext[len-1]=='\n') len--;
00168       nl_error( mode == 2 ? -4 : -3,
00169           "%s%*.*s", ts, len, len, cmdtext);
00170     }
00171   }
00172   if (playback) return(0);
00173   clen = snprintf( buf, CMD_MAX_COMMAND_IN+1, "[%s%s]%s",
00174     cic_header, cmdopts, cmdtext );
00175   if ( clen > CMD_MAX_COMMAND_IN ) {
00176     nl_error( 2, "Command too long" );
00177     return CMDREP_SYNERR;
00178   }
00179   rv = write( cis_fd, buf, clen );
00180   if (rv == -1) {
00181     switch (errno) {
00182       case ENOENT: /* Expected quit condition */
00183         close(cis_fd);
00184         cis_fd = -1;
00185         sent_quit = 1;
00186         return CMDREP_QUIT;
00187       case E2BIG:
00188         nl_error( 4, "Unexpected E2BIG from cis" );
00189       case EINVAL:
00190     if ( nl_response )
00191       nl_error( 2, "Syntax error from cis" );
00192         return CMDREP_SYNERR;
00193       case EIO:
00194         if ( nl_response )
00195       nl_error( 2, "Execution error from cis" );
00196         return CMDREP_EXECERR;
00197       default:
00198         nl_error( 3, "Unhandled error %d from cis", errno );
00199     }
00200     return(1);
00201   }
00202   return 0;
00203 }
00204 
00205 /*
00206 =Name cic_options(): Command line initializations for Command Clients
00207 =Subject Command Server and Client
00208 =Subject Startup
00209 =Synopsis
00210 
00211 #include "nortlib.h"
00212 void cic_options(int argcc, char **argvv, const char *def_prefix);
00213 
00214 =Description
00215 
00216   cic_options() handles command-line initializations for Command
00217   Clients (i.e. processes which will be sending commands to a
00218   Command Server generated via CMDGEN.). It handles the 'C', 'h'
00219   and 'p' options. ('h' actually belongs to the msg library, but
00220   if it has been specified, we want to know about it.)
00221 
00222 =Returns
00223   Nothing.
00224 
00225 =SeeAlso
00226   =Command Server and Client= functions.
00227 
00228 =End
00229 
00230 =Name cic_init(): Locate Command Server
00231 =Subject Command Server and Client
00232 =Subject Startup
00233 =Synopsis
00234 #include "nortlib.h"
00235 int cic_init(void);
00236 
00237 =Description
00238 cic_init() Locates the Command Interpreter Server (CIS) using
00239 either the default node information or the information set
00240 by cic_options -C node. Once located, if ci_version is
00241 non-empty, the version is queried. cic_init() uses the
00242 standard =nl_response= codes to determine whether fatal
00243 response is required.
00244 
00245 =Returns
00246 Returns zero on success.
00247 
00248 =SeeAlso
00249   =Command Server and Client= functions.
00250 
00251 =End
00252 
00253 =Name cic_query(): Get version information from Command Server
00254 =Subject Command Server and Client
00255 =Synopsis
00256 #include "nortlib.h"
00257 int cic_query(char *version);
00258 
00259 =Description
00260   cic_query queries the command server for version information.
00261   If successful, the version of the server is written into the
00262   buffer pointed to by the version argument.
00263 
00264 =Returns
00265   Returns zero on success.
00266 
00267 =SeeAlso
00268   =Command Server and Client= functions.
00269 
00270 =End
00271 
00272 =Name ci_settime(): Update command client's time
00273 =Subject Command Server and Client
00274 =Name ci_time_str(): Retrieve algorithm time string
00275 =Subject Command Server and Client
00276 =Synopsis
00277 #include "nortlib.h"
00278 void ci_settime( long int time );
00279 const char *ci_time_str( void );
00280 
00281 =Description
00282 
00283 ci_settime is an internal function used to update a command
00284 client's time. This is used during playback of algorithms to
00285 allow outbound commands to be logged with their TM time instead
00286 of the current time.
00287 
00288 ci_time_str() returns a string which is appropriate for
00289 output of algorithm time when in playback mode. If not
00290 in playback mode, or if ci_settime() has not yet been
00291 called, an empty string is returned.
00292 
00293 =Returns
00294   ci_settime() return nothing. ci_time_str() returns a
00295   string.
00296 
00297 =SeeAlso
00298   =Command Server and Client= functions.
00299 
00300 =End
00301 
00302 =Name ci_sendcmd(): Send command to Command Server
00303 =Subject Command Server and Client
00304 =Synopsis
00305 #include "nortlib.h"
00306 #include "cmdalgo.h"
00307 
00308 int ci_sendcmd(const char *cmdtext, int mode);
00309 
00310 =Description
00311 
00312 ci_sendcmd() is the basic method to send a command to a
00313 CMDGEN-generated Command Server. cmdtext is a NUL-terminated
00314 ASCII string. It should include any terminating newline (e.g.
00315 "Quit\n") or the command will not actually be executed. The
00316 string must conform to the syntax specified in the CMDGEN input
00317 for the particular server or a syntax error will occur.<P>
00318 
00319 If cmdtext is NULL, a syntax-independent quit request is sent to
00320 the server.<P>
00321 
00322 The mode argument takes on the following values:
00323 
00324 <DL>
00325   <DT>CMDINTERP_SEND (0)
00326   <DD>Execute the command and log it to memo via msg().
00327   <DT>CMDINTERP_TEST (1)
00328   <DD>Check the command for syntax only, but do not execute it
00329   or log it.
00330   <DT>CMDINTERP_SEND_QUIET (2)
00331   <DD>Execute the command but do not log it to memo.
00332 </DL>
00333 
00334 =Returns
00335   Returns zero on success. If the command server cannot be
00336   located (and =nl_response= is set below 3) returns 1.
00337   Otherwise, the return value is the sum of a type code and a
00338   value. The possible types are CMDREP_QUIT, CMDREP_SYNERR and
00339   CMDREP_EXECERR. CMDREP_QUIT indicates that the command you sent
00340   was a quit request, which probably means the client should shut
00341   down also. CMDREP_SYNERR indicates there was a syntax error in
00342   the command you sent. The value portion of the return code is
00343   the offset within the command where the error occurred.
00344   CMDREP_EXECERR indicates that an error occurred when the server
00345   was executing the instructions associated with the command. The
00346   value portion of the return code is the error code.
00347 
00348 =SeeAlso
00349   =ci_sendfcmd=(), =ci_settime=(), =ci_time_str=(), and
00350   =Command Server and Client= functions.
00351 
00352 =End
00353 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines