00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <unistd.h>
00034 #include <signal.h>
00035
00036 #include <iostream>
00037 #include <string>
00038 #include <fstream>
00039
00040 using std::cout ;
00041 using std::cerr ;
00042 using std::endl ;
00043 using std::flush ;
00044 using std::string ;
00045 using std::ofstream ;
00046
00047 #include "CmdApp.h"
00048 #include "CmdClient.h"
00049 #include "PPTException.h"
00050 #include "BESDebug.h"
00051
00052 #define BES_CMDLN_DEFAULT_TIMEOUT 5
00053
00054 CmdApp::CmdApp()
00055 : BESBaseApp(),
00056 _client( 0 ),
00057 _hostStr( "" ),
00058 _unixStr( "" ),
00059 _portVal( 0 ),
00060 _outputStrm( 0 ),
00061 _inputStrm( 0 ),
00062 _createdInputStrm( false ),
00063 _timeout( 0 ),
00064 _repeat( 0 )
00065 {
00066 }
00067
00068 CmdApp::~CmdApp()
00069 {
00070 if( _client )
00071 {
00072 delete _client ;
00073 _client = 0 ;
00074 }
00075 }
00076
00077 void
00078 CmdApp::showVersion()
00079 {
00080 cout << appName() << ": version 2.0" << endl ;
00081 }
00082
00083 void
00084 CmdApp::showUsage( )
00085 {
00086 cout << endl ;
00087 cout << appName() << ": the following flags are available:" << endl ;
00088 cout << " -h <host> - specifies a host for TCP/IP connection" << endl ;
00089 cout << " -p <port> - specifies a port for TCP/IP connection" << endl ;
00090 cout << " -u <unixSocket> - specifies a unix socket for connection. " << endl ;
00091 cout << " -x <command> - specifies a command for the server to execute" << endl ;
00092 cout << " -i <inputFile> - specifies a file name for a sequence of input commands" << endl ;
00093 cout << " -f <outputFile> - specifies a file name to output the results of the input" << endl ;
00094 cout << " -t <timeoutVal> - specifies an optional timeout value in seconds" << endl ;
00095 cout << " -d - sets the optional debug flag for the client session" << endl ;
00096 cout << " -r <num> - repeat the command(s) num times" << endl ;
00097 cout << " -? - display this list of flags" << endl ;
00098 cout << endl ;
00099 BESDebug::Help( cout ) ;
00100 }
00101
00102 void
00103 CmdApp::signalCannotConnect( int sig )
00104 {
00105 if( sig == SIGCONT )
00106 {
00107 CmdApp *app = dynamic_cast<CmdApp *>(BESApp::TheApplication()) ;
00108 if( app )
00109 {
00110 CmdClient *client = app->client() ;
00111 if( client && !client->isConnected() )
00112 {
00113 cout << BESApp::TheApplication()->appName()
00114 << ": No response, server may be down or "
00115 << "busy with another incoming connection. exiting!\n" ;
00116 exit( 1 ) ;
00117 }
00118 }
00119 }
00120 }
00121
00122 void
00123 CmdApp::signalInterrupt( int sig )
00124 {
00125 if( sig == SIGINT )
00126 {
00127 cout << BESApp::TheApplication()->appName()
00128 << ": Please type exit to terminate the session" << endl ;
00129 }
00130 if( signal( SIGINT, CmdApp::signalInterrupt ) == SIG_ERR )
00131 {
00132 cerr << BESApp::TheApplication()->appName()
00133 << ": Could not re-register signal\n" ;
00134 }
00135 }
00136
00137 void
00138 CmdApp::signalTerminate( int sig )
00139 {
00140 if( sig == SIGTERM )
00141 {
00142 cout << BESApp::TheApplication()->appName()
00143 << ": Please type exit to terminate the session" << endl ;
00144 }
00145 if( signal( SIGTERM, CmdApp::signalTerminate ) == SIG_ERR )
00146 {
00147 cerr << BESApp::TheApplication()->appName()
00148 << ": Could not re-register signal\n" ;
00149 }
00150 }
00151
00152 void
00153 CmdApp::signalBrokenPipe( int sig )
00154 {
00155 if( sig == SIGPIPE )
00156 {
00157 cout << BESApp::TheApplication()->appName()
00158 << ": got a broken pipe, server may be down or the port invalid."
00159 << endl
00160 << "Please check parameters and try again" << endl ;
00161 CmdApp *app = dynamic_cast<CmdApp *>(BESApp::TheApplication()) ;
00162 if( app )
00163 {
00164 CmdClient *client = app->client() ;
00165 if( client )
00166 {
00167 client->brokenPipe() ;
00168 client->shutdownClient() ;
00169 delete client;
00170 client = 0;
00171 }
00172 }
00173 exit( 1 ) ;
00174 }
00175 }
00176
00177 void
00178 CmdApp::registerSignals()
00179 {
00180
00181 BESDEBUG( "cmdln", "CmdApp: Registering signal SIGCONT ... " )
00182 if( signal( SIGCONT, signalCannotConnect ) == SIG_ERR )
00183 {
00184 BESDEBUG( "cmdln", "FAILED" << endl ) ;
00185 cerr << appName() << "Failed to register signal SIGCONT" << endl ;
00186 exit( 1 ) ;
00187 }
00188 BESDEBUG( "cmdln", "OK" << endl ) ;
00189
00190
00191
00192 BESDEBUG( "cmdln", "CmdApp: Registering signal SIGINT ... " )
00193 if( signal( SIGINT, signalInterrupt ) == SIG_ERR )
00194 {
00195 BESDEBUG( "cmdln", "FAILED" << endl ) ;
00196 cerr << appName() << "Failed to register signal SIGINT" << endl ;
00197 exit( 1 ) ;
00198 }
00199 BESDEBUG( "cmdln", "OK" << endl ) ;
00200
00201
00202
00203 BESDEBUG( "cmdln", "CmdApp: Registering signal SIGTERM ... " )
00204 if( signal( SIGTERM, signalTerminate ) == SIG_ERR )
00205 {
00206 BESDEBUG( "cmdln", "FAILED" << endl ) ;
00207 cerr << appName() << "Failed to register signal SIGTERM" << endl ;
00208 exit( 1 ) ;
00209 }
00210 BESDEBUG( "cmdln", "OK" << endl ) ;
00211
00212
00213 BESDEBUG( "cmdln", "CmdApp: Registering signal SIGPIPE ... " )
00214 if( signal( SIGPIPE, CmdApp::signalBrokenPipe ) == SIG_ERR )
00215 {
00216 BESDEBUG( "cmdln", "FAILED" << endl ) ;
00217 cerr << appName() << "Failed to register signal SIGPIPE" << endl ;
00218 exit( 1 ) ;
00219 }
00220 BESDEBUG( "cmdln", "OK" << endl ) ;
00221 }
00222
00223 int
00224 CmdApp::initialize( int argc, char **argv )
00225 {
00226 int retVal = BESBaseApp::initialize( argc, argv ) ;
00227 if( retVal != 0 )
00228 return retVal ;
00229
00230 string portStr = "" ;
00231 string outputStr = "" ;
00232 string inputStr = "" ;
00233 string timeoutStr = "" ;
00234 string repeatStr = "" ;
00235
00236 bool badUsage = false ;
00237
00238 int c ;
00239
00240 while( ( c = getopt( argc, argv, "?vd:h:p:t:u:x:f:i:r:" ) ) != EOF )
00241 {
00242 switch( c )
00243 {
00244 case 't':
00245 timeoutStr = optarg ;
00246 break ;
00247 case 'h':
00248 _hostStr = optarg ;
00249 break ;
00250 case 'd':
00251 BESDebug::SetUp( optarg ) ;
00252 break ;
00253 case 'v':
00254 {
00255 showVersion() ;
00256 exit( 0 ) ;
00257 }
00258 break ;
00259 case 'p':
00260 portStr = optarg ;
00261 break ;
00262 case 'u':
00263 _unixStr = optarg ;
00264 break ;
00265 case 'x':
00266 _cmd = optarg ;
00267 break ;
00268 case 'f':
00269 outputStr = optarg ;
00270 break ;
00271 case 'i':
00272 inputStr = optarg ;
00273 break ;
00274 case 'r':
00275 repeatStr = optarg ;
00276 break ;
00277 case '?':
00278 {
00279 showUsage() ;
00280 exit( 0 ) ;
00281 }
00282 break ;
00283 }
00284 }
00285 if( _hostStr == "" && _unixStr == "" )
00286 {
00287 cerr << "host/port or unix socket must be specified" << endl ;
00288 badUsage = true ;
00289 }
00290
00291 if( _hostStr != "" && _unixStr != "" )
00292 {
00293 cerr << "must specify either a host and port or a unix socket" << endl ;
00294 badUsage = true ;
00295 }
00296
00297 if( portStr != "" && _unixStr != "" )
00298 {
00299 cerr << "must specify either a host and port or a unix socket" << endl ;
00300 badUsage = true ;
00301 }
00302
00303 if( _hostStr != "" )
00304 {
00305 if( portStr == "" )
00306 {
00307 cout << "port must be specified when specifying a host" << endl ;
00308 badUsage = true ;
00309 }
00310 else
00311 {
00312 _portVal = atoi( portStr.c_str() ) ;
00313 }
00314 }
00315
00316 if( timeoutStr != "" )
00317 {
00318 _timeout = atoi( timeoutStr.c_str() ) ;
00319 }
00320 else
00321 {
00322 _timeout = BES_CMDLN_DEFAULT_TIMEOUT ;
00323 }
00324
00325 if( outputStr != "" )
00326 {
00327 if( _cmd == "" && inputStr == "" )
00328 {
00329 cerr << "When specifying an output file you must either "
00330 << "specify a command or an input file"
00331 << endl ;
00332 badUsage = true ;
00333 }
00334 else if( _cmd != "" && inputStr != "" )
00335 {
00336 cerr << "You must specify either a command or an input file on "
00337 << "the command line, not both"
00338 << endl ;
00339 badUsage = true ;
00340 }
00341 }
00342
00343 if( badUsage == true )
00344 {
00345 showUsage( ) ;
00346 return 1 ;
00347 }
00348
00349 if( outputStr != "" )
00350 {
00351 _outputStrm = new ofstream( outputStr.c_str() ) ;
00352 if( !(*_outputStrm) )
00353 {
00354 cerr << "could not open the output file " << outputStr << endl ;
00355 badUsage = true ;
00356 }
00357 }
00358
00359 if( inputStr != "" )
00360 {
00361 _inputStrm = new ifstream( inputStr.c_str() ) ;
00362 if( !(*_inputStrm) )
00363 {
00364 cerr << "could not open the input file " << inputStr << endl ;
00365 badUsage = true ;
00366 }
00367 _createdInputStrm = true ;
00368 }
00369
00370 if( !repeatStr.empty() )
00371 {
00372 _repeat = atoi( repeatStr.c_str() ) ;
00373 if( !_repeat && repeatStr != "0" )
00374 {
00375 cerr << "repeat number invalid: " << repeatStr << endl ;
00376 badUsage = true ;
00377 }
00378 if( !_repeat )
00379 {
00380 _repeat = 1 ;
00381 }
00382 }
00383
00384 if( badUsage == true )
00385 {
00386 showUsage( ) ;
00387 return 1 ;
00388 }
00389
00390 registerSignals() ;
00391
00392 BESDEBUG( "cmdln", "CmdApp: initialized settings:" << endl << *this ) ;
00393
00394 return 0 ;
00395 }
00396
00397 int
00398 CmdApp::run()
00399 {
00400 try
00401 {
00402 _client = new CmdClient( ) ;
00403 if( _hostStr != "" )
00404 {
00405 BESDEBUG( "cmdln", "CmdApp: Connecting to host: " << _hostStr
00406 << " at port: " << _portVal << " ... " ) ;
00407 _client->startClient( _hostStr, _portVal, _timeout ) ;
00408 }
00409 else
00410 {
00411 BESDEBUG( "cmdln", "CmdApp: Connecting to unix socket: " << _unixStr
00412 << " ... " ) ;
00413 _client->startClient( _unixStr, _timeout ) ;
00414 }
00415
00416 if( _outputStrm )
00417 {
00418 _client->setOutput( _outputStrm, true ) ;
00419 }
00420 else
00421 {
00422 _client->setOutput( &cout, false ) ;
00423 }
00424 BESDEBUG( "cmdln", "OK" << endl ) ;
00425 }
00426 catch( PPTException &e )
00427 {
00428 if( _client )
00429 {
00430 _client->shutdownClient() ;
00431 delete _client ;
00432 _client = 0 ;
00433 }
00434 BESDEBUG( "cmdln", "FAILED" << endl ) ;
00435 cerr << "error starting the client" << endl ;
00436 cerr << e.getMessage() << endl ;
00437 exit( 1 ) ;
00438 }
00439
00440 try
00441 {
00442 if( _cmd != "" )
00443 {
00444 _client->executeCommands( _cmd, _repeat ) ;
00445 }
00446 else if( _inputStrm )
00447 {
00448 _client->executeCommands( *_inputStrm, _repeat ) ;
00449 }
00450 else
00451 {
00452 _client->interact() ;
00453 }
00454 }
00455 catch( PPTException &e )
00456 {
00457 cerr << "error processing commands" << endl ;
00458 cerr << e.getMessage() << endl ;
00459 }
00460
00461 try
00462 {
00463 BESDEBUG( "cmdln", "CmdApp: shutting down client ... " ) ;
00464 if( _client )
00465 {
00466 _client->shutdownClient() ;
00467 delete _client ;
00468 _client = 0 ;
00469 }
00470 BESDEBUG( "cmdln", "OK" << endl ) ;
00471
00472 BESDEBUG( "cmdln", "CmdApp: closing input stream ... " ) ;
00473 if( _createdInputStrm )
00474 {
00475 _inputStrm->close() ;
00476 delete _inputStrm ;
00477 _inputStrm = 0 ;
00478 }
00479 BESDEBUG( "cmdln", "OK" << endl ) ;
00480 }
00481 catch( PPTException &e )
00482 {
00483 BESDEBUG( "cmdln", "FAILED" << endl ) ;
00484 cerr << "error closing the client" << endl ;
00485 cerr << e.getMessage() << endl ;
00486 return 1 ;
00487 }
00488
00489 return 0 ;
00490 }
00491
00498 void
00499 CmdApp::dump( ostream &strm ) const
00500 {
00501 strm << BESIndent::LMarg << "CmdApp::dump - ("
00502 << (void *)this << ")" << endl ;
00503 BESIndent::Indent() ;
00504 if( _client )
00505 {
00506 strm << BESIndent::LMarg << "client: " << endl ;
00507 BESIndent::Indent() ;
00508 _client->dump( strm ) ;
00509 BESIndent::UnIndent() ;
00510 }
00511 else
00512 {
00513 strm << BESIndent::LMarg << "client: null" << endl ;
00514 }
00515 strm << BESIndent::LMarg << "host: " << _hostStr << endl ;
00516 strm << BESIndent::LMarg << "unix socket: " << _unixStr << endl ;
00517 strm << BESIndent::LMarg << "port: " << _portVal << endl ;
00518 strm << BESIndent::LMarg << "command: " << _cmd << endl ;
00519 strm << BESIndent::LMarg << "output stream: " << (void *)_outputStrm << endl ;
00520 strm << BESIndent::LMarg << "input stream: " << (void *)_inputStrm << endl ;
00521 strm << BESIndent::LMarg << "created input stream? " << _createdInputStrm << endl ;
00522 strm << BESIndent::LMarg << "timeout: " << _timeout << endl ;
00523 BESBaseApp::dump( strm ) ;
00524 BESIndent::UnIndent() ;
00525 }
00526
00527 int
00528 main( int argc, char **argv )
00529 {
00530 CmdApp app ;
00531 return app.main( argc, argv ) ;
00532 }
00533