ARPDAS_QNX6 1.0
|
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 */