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