OPeNDAP Hyrax Back End Server (BES)
Updated for version 3.8.3
|
00001 // ServerApp.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 00032 00033 #include <signal.h> 00034 #include <unistd.h> // for getpid 00035 #include <grp.h> // for getgrnam 00036 #include <pwd.h> // for getpwnam 00037 00038 #include <iostream> 00039 #include <fstream> 00040 #include <sstream> 00041 #include <cstdlib> 00042 00043 using std::cout ; 00044 using std::cerr ; 00045 using std::endl ; 00046 using std::ios ; 00047 using std::ostringstream ; 00048 using std::ofstream ; 00049 00050 #include "config.h" 00051 00052 #include "ServerApp.h" 00053 #include "ServerExitConditions.h" 00054 #include "TheBESKeys.h" 00055 #include "BESLog.h" 00056 #include "SocketListener.h" 00057 #include "TcpSocket.h" 00058 #include "UnixSocket.h" 00059 #include "BESServerHandler.h" 00060 #include "BESError.h" 00061 #include "PPTServer.h" 00062 #include "BESMemoryManager.h" 00063 #include "BESDebug.h" 00064 #include "BESServerUtils.h" 00065 00066 #include "BESDefaultModule.h" 00067 #include "BESXMLDefaultCommands.h" 00068 00069 ServerApp::ServerApp() 00070 : BESModuleApp(), 00071 _portVal( 0 ), 00072 _gotPort( false ), 00073 _unixSocket( "" ), 00074 _secure( false ), 00075 _mypid( 0 ), 00076 _ts( 0 ), 00077 _us( 0 ), 00078 _ps( 0 ) 00079 { 00080 _mypid = getpid() ; 00081 } 00082 00083 ServerApp::~ServerApp() 00084 { 00085 } 00086 00087 void 00088 ServerApp::signalTerminate( int sig ) 00089 { 00090 if( sig == SIGTERM ) 00091 { 00092 BESApp::TheApplication()->terminate( sig ) ; 00093 exit( SERVER_EXIT_NORMAL_SHUTDOWN ) ; 00094 } 00095 } 00096 00097 void 00098 ServerApp::signalInterrupt( int sig ) 00099 { 00100 if( sig == SIGINT ) 00101 { 00102 BESApp::TheApplication()->terminate( sig ) ; 00103 exit( SERVER_EXIT_NORMAL_SHUTDOWN ) ; 00104 } 00105 } 00106 00107 void 00108 ServerApp::signalRestart( int sig ) 00109 { 00110 if( sig == SIGUSR1 ) 00111 { 00112 BESApp::TheApplication()->terminate( sig ) ; 00113 exit( SERVER_EXIT_RESTART ) ; 00114 } 00115 } 00116 00117 void 00118 ServerApp::set_group_id() 00119 { 00120 #if !defined(OS2) && !defined(TPF) 00121 // OS/2 and TPF don't support groups. 00122 00123 // get group id or name from BES configuration file 00124 // If BES.Group begins with # then it is a group id, 00125 // else it is a group name and look up the id. 00126 BESDEBUG( "server", "ServerApp: Setting group id ... " << endl ) ; 00127 bool found = false ; 00128 string key = "BES.Group" ; 00129 string group_str ; 00130 try 00131 { 00132 TheBESKeys::TheKeys()->get_value( key, group_str, found ) ; 00133 } 00134 catch( BESError &e ) 00135 { 00136 BESDEBUG( "server", "FAILED" << endl ) ; 00137 string err = string("FAILED: ") + e.get_message() ; 00138 cerr << err << endl ; 00139 (*BESLog::TheLog()) << err << endl ; 00140 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00141 } 00142 if( !found || group_str.empty() ) 00143 { 00144 BESDEBUG( "server", "FAILED" << endl ) ; 00145 string err = "FAILED: Group not specified in BES configuration file" ; 00146 cerr << err << endl ; 00147 (*BESLog::TheLog()) << err << endl ; 00148 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00149 } 00150 BESDEBUG( "server", "to " << group_str << " ... " << endl ) ; 00151 00152 gid_t new_gid = 0 ; 00153 if( group_str[0] == '#' ) 00154 { 00155 // group id starts with a #, so is a group id 00156 const char *group_c = group_str.c_str() ; 00157 group_c++ ; 00158 new_gid = atoi( group_c ) ; 00159 } 00160 else 00161 { 00162 // specified group is a group name 00163 struct group *ent ; 00164 ent = getgrnam( group_str.c_str() ) ; 00165 if( !ent ) 00166 { 00167 BESDEBUG( "server", "FAILED" << endl ) ; 00168 string err = (string)"FAILED: Group " + group_str 00169 + " does not exist" ; 00170 cerr << err << endl ; 00171 (*BESLog::TheLog()) << err << endl ; 00172 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00173 } 00174 new_gid = ent->gr_gid ; 00175 } 00176 00177 if( new_gid < 1 ) 00178 { 00179 BESDEBUG( "server", "FAILED" << endl ) ; 00180 ostringstream err ; 00181 err << "FAILED: Group id " << new_gid 00182 << " not a valid group id for BES" ; 00183 cerr << err.str() << endl ; 00184 (*BESLog::TheLog()) << err.str() << endl ; 00185 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00186 } 00187 00188 BESDEBUG( "server", "to id " << new_gid << " ... " << endl ) ; 00189 if( setgid( new_gid ) == -1 ) 00190 { 00191 BESDEBUG( "server", "FAILED" << endl ) ; 00192 ostringstream err ; 00193 err << "FAILED: unable to set the group id to " << new_gid ; 00194 cerr << err.str() << endl ; 00195 (*BESLog::TheLog()) << err.str() << endl ; 00196 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00197 } 00198 00199 BESDEBUG( "server", "OK" << endl ) ; 00200 #else 00201 BESDEBUG( "server", "ServerApp: Groups not supported in this OS" << endl ) ; 00202 #endif 00203 } 00204 00205 void 00206 ServerApp::set_user_id() 00207 { 00208 BESDEBUG( "server", "ServerApp: Setting user id ... " << endl ) ; 00209 00210 // Get user name or id from the BES configuration file. 00211 // If the BES.User value begins with # then it is a user 00212 // id, else it is a user name and need to look up the 00213 // user id. 00214 bool found = false ; 00215 string key = "BES.User" ; 00216 string user_str ; 00217 try 00218 { 00219 TheBESKeys::TheKeys()->get_value( key, user_str, found ) ; 00220 } 00221 catch( BESError &e ) 00222 { 00223 BESDEBUG( "server", "FAILED" << endl ) ; 00224 string err = (string)"FAILED: " + e.get_message() ; 00225 cerr << err << endl ; 00226 (*BESLog::TheLog()) << err << endl ; 00227 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00228 } 00229 if( !found || user_str.empty() ) 00230 { 00231 BESDEBUG( "server", "FAILED" << endl ) ; 00232 string err = (string)"FAILED: User not specified in BES config file" ; 00233 cerr << err << endl ; 00234 (*BESLog::TheLog()) << err << endl ; 00235 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00236 } 00237 BESDEBUG( "server", "to " << user_str << " ... " << endl ) ; 00238 00239 uid_t new_id = 0 ; 00240 if( user_str[0] == '#' ) 00241 { 00242 const char *user_str_c = user_str.c_str() ; 00243 user_str_c++ ; 00244 new_id = atoi( user_str_c ) ; 00245 } 00246 else 00247 { 00248 struct passwd *ent ; 00249 ent = getpwnam( user_str.c_str() ) ; 00250 if( !ent ) 00251 { 00252 BESDEBUG( "server", "FAILED" << endl ) ; 00253 string err = (string)"FAILED: Bad user name specified: " 00254 + user_str ; 00255 cerr << err << endl ; 00256 (*BESLog::TheLog()) << err << endl ; 00257 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00258 } 00259 new_id = ent->pw_uid ; 00260 } 00261 00262 // new user id cannot be root (0) 00263 if( !new_id ) 00264 { 00265 BESDEBUG( "server", "FAILED" << endl ) ; 00266 string err = (string)"FAILED: BES cannot run as root" ; 00267 cerr << err << endl ; 00268 (*BESLog::TheLog()) << err << endl ; 00269 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00270 } 00271 00272 BESDEBUG( "server", "to " << new_id << " ... " << endl ) ; 00273 if( setuid( new_id ) == -1 ) 00274 { 00275 BESDEBUG( "server", "FAILED" << endl ) ; 00276 ostringstream err ; 00277 err << "FAILED: Unable to set user id to " << new_id ; 00278 cerr << err.str() << endl ; 00279 (*BESLog::TheLog()) << err.str() << endl ; 00280 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00281 } 00282 } 00283 00284 int 00285 ServerApp::initialize( int argc, char **argv ) 00286 { 00287 int c = 0 ; 00288 bool needhelp = false ; 00289 string dashi ; 00290 string dashc ; 00291 00292 // If you change the getopt statement below, be sure to make the 00293 // corresponding change in daemon.cc and besctl.in 00294 while( ( c = getopt( argc, argv, "hvsd:c:p:u:i:r:" ) ) != EOF ) 00295 { 00296 switch( c ) 00297 { 00298 case 'i': 00299 dashi = optarg ; 00300 break ; 00301 case 'c': 00302 dashc = optarg ; 00303 break ; 00304 case 'r': 00305 break ; // we can ignore the /var/run directory option here 00306 case 'p': 00307 _portVal = atoi( optarg ) ; 00308 _gotPort = true ; 00309 break ; 00310 case 'u': 00311 _unixSocket = optarg ; 00312 break ; 00313 case 'd': 00314 BESDebug::SetUp( optarg ) ; 00315 break ; 00316 case 'v': 00317 BESServerUtils::show_version( BESApp::TheApplication()->appName() ) ; 00318 break ; 00319 case 's': 00320 _secure = true ; 00321 break ; 00322 case 'h': 00323 case '?': 00324 default: 00325 needhelp = true ; 00326 break ; 00327 } 00328 } 00329 00330 // before we can do any processing, log any messages, initialize any 00331 // modules, do anything, we need to determine where the BES 00332 // configuration file lives. From here we get the name of the log 00333 // file, group and user id, and information that the modules will 00334 // need to run properly. 00335 00336 // If the -c optiion was passed, set the config file name in TheBESKeys 00337 if( !dashc.empty() ) 00338 { 00339 TheBESKeys::ConfigFile = dashc ; 00340 } 00341 00342 // If the -c option was not passed, but the -i option 00343 // was passed, then use the -i option to construct 00344 // the path to the config file 00345 if( dashc.empty() && !dashi.empty() ) 00346 { 00347 if( dashi[dashi.length()-1] != '/' ) 00348 { 00349 dashi += '/' ; 00350 } 00351 string conf_file = dashi + "etc/bes/bes.conf" ; 00352 TheBESKeys::ConfigFile = conf_file ; 00353 } 00354 00355 // Now that we have the configuration information, we can log to the 00356 // BES log file if there are errors in starting up, etc... 00357 00358 uid_t curr_euid = geteuid() ; 00359 #ifndef BES_DEVELOPER 00360 // must be root to run this app and to set user id and group id later 00361 if( curr_euid ) 00362 { 00363 string err = "FAILED: Must be root to run BES" ; 00364 cerr << err << endl ; 00365 (*BESLog::TheLog()) << err << endl ; 00366 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00367 } 00368 #else 00369 cout << "Developer Mode: not testing if BES is run by root" << endl ; 00370 #endif 00371 00372 // register the two debug context for the server and ppt. The 00373 // Default Module will register the bes context. 00374 BESDebug::Register( "server" ) ; 00375 BESDebug::Register( "ppt" ) ; 00376 00377 // Before we can load modules, start writing to the BES log 00378 // file, etc... we need to run as the proper user. Set the user 00379 // id and the group id to what is specified in the BES 00380 // configuration file 00381 if( curr_euid == 0 ) 00382 { 00383 #ifdef BES_DEVELOPER 00384 cout << "Developer Mode: Running as root - setting group and user ids" 00385 << endl ; 00386 #endif 00387 set_group_id() ; 00388 set_user_id() ; 00389 } 00390 else 00391 { 00392 cout << "Developer Mode: Not setting group or user ids" << endl ; 00393 } 00394 00395 // Because we are now running as the user specified in the 00396 // configuraiton file, we won't be able to listen on system ports. 00397 // If this is a problem, we may need to move this code above setting 00398 // the user and group ids. 00399 bool found = false ; 00400 string port_key = "BES.ServerPort" ; 00401 if( !_gotPort ) 00402 { 00403 string sPort ; 00404 try 00405 { 00406 TheBESKeys::TheKeys()->get_value( port_key, sPort, found ) ; 00407 } 00408 catch( BESError &e ) 00409 { 00410 BESDEBUG( "server", "FAILED" << endl ) ; 00411 string err = (string)"FAILED: " + e.get_message() ; 00412 cerr << err << endl ; 00413 (*BESLog::TheLog()) << err << endl ; 00414 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00415 } 00416 if( found ) 00417 { 00418 _portVal = atoi( sPort.c_str() ) ; 00419 if( _portVal != 0 ) 00420 { 00421 _gotPort = true ; 00422 } 00423 } 00424 } 00425 00426 found = false ; 00427 string socket_key = "BES.ServerUnixSocket" ; 00428 if( _unixSocket == "" ) 00429 { 00430 try 00431 { 00432 TheBESKeys::TheKeys()->get_value( socket_key, _unixSocket, found ) ; 00433 } 00434 catch( BESError &e ) 00435 { 00436 BESDEBUG( "server", "FAILED" << endl ) ; 00437 string err = (string)"FAILED: " + e.get_message() ; 00438 cerr << err << endl ; 00439 (*BESLog::TheLog()) << err << endl ; 00440 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00441 } 00442 } 00443 00444 if( !_gotPort && _unixSocket == "" ) 00445 { 00446 string msg = "Must specify a tcp port or a unix socket or both\n" ; 00447 msg += "Please specify on the command line with -p <port>" ; 00448 msg += " and/or -u <unix_socket>\n" ; 00449 msg += "Or specify in the bes configuration file with " 00450 + port_key + " and/or " + socket_key + "\n" ; 00451 cout << endl << msg ; 00452 (*BESLog::TheLog()) << msg << endl ; 00453 BESServerUtils::show_usage( BESApp::TheApplication()->appName() ) ; 00454 } 00455 00456 found = false ; 00457 if( _secure == false ) 00458 { 00459 string key = "BES.ServerSecure" ; 00460 string isSecure ; 00461 try 00462 { 00463 TheBESKeys::TheKeys()->get_value( key, isSecure, found ) ; 00464 } 00465 catch( BESError &e ) 00466 { 00467 BESDEBUG( "server", "FAILED" << endl ) ; 00468 string err = (string)"FAILED: " + e.get_message() ; 00469 cerr << err << endl ; 00470 (*BESLog::TheLog()) << err << endl ; 00471 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00472 } 00473 if( isSecure == "Yes" || isSecure == "YES" || isSecure == "yes" ) 00474 { 00475 _secure = true ; 00476 } 00477 } 00478 00479 BESDEBUG( "server", "ServerApp: Registering signal SIGTERM ... " << endl ) ; 00480 if( signal( SIGTERM, signalTerminate ) == SIG_ERR ) 00481 { 00482 BESDEBUG( "server", "FAILED" << endl ) ; 00483 string err = "FAILED: cannot register SIGTERM signal handler" ; 00484 cerr << err << endl ; 00485 (*BESLog::TheLog()) << err << endl ; 00486 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00487 } 00488 BESDEBUG( "server", "OK" << endl ) ; 00489 00490 BESDEBUG( "server", "ServerApp: Registering signal SIGINT ... " << endl ) ; 00491 if( signal( SIGINT, signalInterrupt ) == SIG_ERR ) 00492 { 00493 BESDEBUG( "server", "FAILED" << endl ) ; 00494 string err = "FAILED: cannot register SIGINT signal handler" ; 00495 cerr << err << endl ; 00496 (*BESLog::TheLog()) << err << endl ; 00497 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00498 } 00499 BESDEBUG( "server", "OK" << endl ) ; 00500 00501 BESDEBUG( "server", "ServerApp: Registering signal SIGUSR1 ... " << endl ) ; 00502 if( signal( SIGUSR1, signalRestart ) == SIG_ERR ) 00503 { 00504 BESDEBUG( "server", "FAILED" << endl ) ; 00505 string err = "FAILED: cannot register SIGUSR1 signal handler" ; 00506 cerr << err << endl ; 00507 (*BESLog::TheLog()) << err << endl ; 00508 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ; 00509 } 00510 BESDEBUG( "server", "OK" << endl ) ; 00511 00512 BESDEBUG( "server", "ServerApp: initializing default module ... " 00513 << endl ) ; 00514 BESDefaultModule::initialize( argc, argv ) ; 00515 BESDEBUG( "server", "OK" << endl ) ; 00516 00517 BESDEBUG( "server", "ServerApp: initializing default commands ... " 00518 << endl ) ; 00519 BESXMLDefaultCommands::initialize( argc, argv ) ; 00520 BESDEBUG( "server", "OK" << endl ) ; 00521 00522 // This will load and initialize all of the modules 00523 int ret = BESModuleApp::initialize( argc, argv ) ; 00524 00525 BESDEBUG( "server", "ServerApp: initialized settings:" << *this ) ; 00526 00527 if( needhelp ) 00528 { 00529 BESServerUtils::show_usage( BESApp::TheApplication()->appName() ) ; 00530 } 00531 00532 return ret ; 00533 } 00534 00535 int 00536 ServerApp::run() 00537 { 00538 try 00539 { 00540 BESDEBUG( "server", "ServerApp: initializing memory pool ... " 00541 << endl ) ; 00542 BESMemoryManager::initialize_memory_pool() ; 00543 BESDEBUG( "server", "OK" << endl ) ; 00544 00545 SocketListener listener ; 00546 00547 if( _portVal ) 00548 { 00549 _ts = new TcpSocket( _portVal ) ; 00550 listener.listen( _ts ) ; 00551 BESDEBUG( "server", "ServerApp: listening on port (" 00552 << _portVal << ")" << endl ) ; 00553 } 00554 00555 if( !_unixSocket.empty() ) 00556 { 00557 _us = new UnixSocket( _unixSocket ) ; 00558 listener.listen( _us ) ; 00559 BESDEBUG( "server", "ServerApp: listening on unix socket (" 00560 << _unixSocket << ")" << endl ) ; 00561 } 00562 00563 BESServerHandler handler ; 00564 00565 _ps = new PPTServer( &handler, &listener, _secure ) ; 00566 _ps->initConnection() ; 00567 } 00568 catch( BESError &se ) 00569 { 00570 cerr << se.get_message() << endl ; 00571 (*BESLog::TheLog()) << se.get_message() << endl ; 00572 return 1 ; 00573 } 00574 catch( ... ) 00575 { 00576 cerr << "caught unknown exception" << endl ; 00577 (*BESLog::TheLog()) << "caught unknown exception initializing sockets" 00578 << endl ; 00579 return 1 ; 00580 } 00581 00582 return 0 ; 00583 } 00584 00585 int 00586 ServerApp::terminate( int sig ) 00587 { 00588 pid_t apppid = getpid() ; 00589 if( apppid == _mypid ) 00590 { 00591 if( _ps ) 00592 { 00593 _ps->closeConnection() ; 00594 delete _ps ; 00595 } 00596 if( _ts ) 00597 { 00598 _ts->close() ; 00599 delete _ts ; 00600 } 00601 if( _us ) 00602 { 00603 _us->close() ; 00604 delete _us ; 00605 } 00606 00607 BESDEBUG( "server", "ServerApp: terminating default module ... " 00608 << endl ) ; 00609 BESDefaultModule::terminate( ) ; 00610 BESDEBUG( "server", "OK" << endl ) ; 00611 00612 BESDEBUG( "server", "ServerApp: terminating default commands ... " 00613 << endl ) ; 00614 BESXMLDefaultCommands::terminate( ) ; 00615 BESDEBUG( "server", "OK" << endl ) ; 00616 00617 BESModuleApp::terminate( sig ) ; 00618 } 00619 return sig ; 00620 } 00621 00628 void 00629 ServerApp::dump( ostream &strm ) const 00630 { 00631 strm << BESIndent::LMarg << "ServerApp::dump - (" 00632 << (void *)this << ")" << endl ; 00633 BESIndent::Indent() ; 00634 strm << BESIndent::LMarg << "got port? " << _gotPort << endl ; 00635 strm << BESIndent::LMarg << "port: " << _portVal << endl ; 00636 strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl ; 00637 strm << BESIndent::LMarg << "is secure? " << _secure << endl ; 00638 strm << BESIndent::LMarg << "pid: " << _mypid << endl ; 00639 if( _ts ) 00640 { 00641 strm << BESIndent::LMarg << "tcp socket:" << endl ; 00642 BESIndent::Indent() ; 00643 _ts->dump( strm ) ; 00644 BESIndent::UnIndent() ; 00645 } 00646 else 00647 { 00648 strm << BESIndent::LMarg << "tcp socket: null" << endl ; 00649 } 00650 if( _us ) 00651 { 00652 strm << BESIndent::LMarg << "unix socket:" << endl ; 00653 BESIndent::Indent() ; 00654 _us->dump( strm ) ; 00655 BESIndent::UnIndent() ; 00656 } 00657 else 00658 { 00659 strm << BESIndent::LMarg << "unix socket: null" << endl ; 00660 } 00661 if( _ps ) 00662 { 00663 strm << BESIndent::LMarg << "ppt server:" << endl ; 00664 BESIndent::Indent() ; 00665 _ps->dump( strm ) ; 00666 BESIndent::UnIndent() ; 00667 } 00668 else 00669 { 00670 strm << BESIndent::LMarg << "ppt server: null" << endl ; 00671 } 00672 BESModuleApp::dump( strm ) ; 00673 BESIndent::UnIndent() ; 00674 } 00675 00676 int 00677 main( int argc, char **argv ) 00678 { 00679 try 00680 { 00681 ServerApp app ; 00682 return app.main( argc, argv ) ; 00683 } 00684 catch( BESError &e ) 00685 { 00686 cerr << "Caught unhandled exception: " << endl ; 00687 cerr << e.get_message() << endl ; 00688 return 1 ; 00689 } 00690 catch( ... ) 00691 { 00692 cerr << "Caught unhandled, unknown exception" << endl ; 00693 return 1 ; 00694 } 00695 return 0 ; 00696 } 00697