Go to the documentation of this file.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 <sys/wait.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <ctype.h>
00038
00039 #include <fstream>
00040 #include <iostream>
00041 #include <string>
00042 #include <cstring>
00043 #include <cstdlib>
00044 #include <cerrno>
00045
00046 using std::ifstream ;
00047 using std::ofstream ;
00048 using std::cout ;
00049 using std::endl ;
00050 using std::cerr ;
00051 using std::flush;
00052 using std::string ;
00053
00054 #include "config.h"
00055 #include "ServerExitConditions.h"
00056 #include "BESServerUtils.h"
00057 #include "BESScrub.h"
00058
00059 #define BES_SERVER_ROOT "BES_SERVER_ROOT"
00060 #define BES_SERVER "/beslistener"
00061 #define BES_SERVER_PID "/bes.pid"
00062
00063 int daemon_init() ;
00064 int mount_server( char ** ) ;
00065 int pr_exit( int status ) ;
00066 void store_listener_id( int pid ) ;
00067 bool load_names( const string &install_dir, const string &pid_dir ) ;
00068
00069 string NameProgram ;
00070
00071
00072 string server_name ;
00073 string file_for_listener ;
00074
00075 char **arguments = 0 ;
00076
00077 int
00078 main(int argc, char *argv[])
00079 {
00080 #ifndef BES_DEVELOPER
00081
00082 uid_t curr_euid = geteuid() ;
00083 if( curr_euid )
00084 {
00085 cerr << "FAILED: Must be root to run BES" << endl ;
00086 exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00087 }
00088 #else
00089 cerr << "Developer Mode: not testing if BES is run by root" << endl ;
00090 #endif
00091
00092 NameProgram = argv[0] ;
00093
00094 string install_dir ;
00095 string pid_dir ;
00096
00097
00098
00099 int c = 0 ;
00100
00101
00102
00103 if( argc > 16 )
00104 {
00105
00106 BESServerUtils::show_usage( NameProgram ) ;
00107 }
00108
00109
00110 unsigned short num_args = 1 ;
00111 while( ( c = getopt( argc, argv, "hvsd:c:p:u:i:r:" ) ) != EOF )
00112 {
00113 switch( c )
00114 {
00115 case 'v':
00116 BESServerUtils::show_version( NameProgram ) ;
00117 break ;
00118 case '?':
00119 case 'h':
00120 BESServerUtils::show_usage( NameProgram ) ;
00121 break ;
00122 case 'i':
00123 install_dir = optarg ;
00124 if( BESScrub::pathname_ok( install_dir, true ) == false )
00125 {
00126 cout << "The specified install directory (-i option) "
00127 << "is incorrectly formatted. Must be less than "
00128 << "255 characters and include the characters "
00129 << "[0-9A-z_./-]" << endl ;
00130 return 1 ;
00131 }
00132 num_args+=2 ;
00133 break ;
00134 case 's':
00135 num_args++ ;
00136 break ;
00137 case 'r':
00138 {
00139 pid_dir = optarg ;
00140 if( BESScrub::pathname_ok( pid_dir, true ) == false )
00141 {
00142 cout << "The specified state directory (-r option) "
00143 << "is incorrectly formatted. Must be less than "
00144 << "255 characters and include the characters "
00145 << "[0-9A-z_./-]" << endl ;
00146 return 1 ;
00147 }
00148 num_args+=2 ;
00149 }
00150 break ;
00151 case 'c':
00152 case 'u':
00153 {
00154 string check_path = optarg ;
00155 if( BESScrub::pathname_ok( check_path, true ) == false )
00156 {
00157 cout << "The specified install directory (-i option) "
00158 << "is incorrectly formatted. Must be less than "
00159 << "255 characters and include the characters "
00160 << "[0-9A-z_./-]" << endl ;
00161 return 1 ;
00162 }
00163 num_args+=2 ;
00164 }
00165 break ;
00166 case 'p':
00167 {
00168 string port_num = optarg ;
00169 for( unsigned int i = 0; i < port_num.length(); i++ )
00170 {
00171 if( !isdigit( port_num[i] ) )
00172 {
00173 cout << "The specified port contains non-digit "
00174 << "characters: " << port_num << endl ;
00175 return 1 ;
00176 }
00177 }
00178 num_args+=2 ;
00179 }
00180 break ;
00181 case 'd':
00182 {
00183 string check_arg = optarg ;
00184 if( BESScrub::command_line_arg_ok( check_arg ) == false )
00185 {
00186 cout << "The specified debug options \"" << check_arg
00187 << "\" contains invalid characters" << endl ;
00188 return 1 ;
00189 }
00190 num_args+=2 ;
00191 }
00192 break ;
00193 default:
00194 BESServerUtils::show_usage( NameProgram ) ;
00195 break ;
00196 }
00197 }
00198
00199
00200
00201 if( argc > num_args )
00202 {
00203 cout << NameProgram
00204 << ": too many arguments passed to the BES" ;
00205 BESServerUtils::show_usage( NameProgram ) ;
00206 }
00207
00208 if( pid_dir.empty() )
00209 {
00210 pid_dir = install_dir ;
00211 }
00212
00213
00214 if( !load_names( install_dir, pid_dir ) )
00215 return 1 ;
00216
00217
00218 if( BESScrub::size_ok( sizeof( char *), num_args+1 ) == false )
00219 {
00220 cout << NameProgram
00221 << ": too many arguments passed to the BES" ;
00222 BESServerUtils::show_usage( NameProgram ) ;
00223 }
00224 arguments = new char *[num_args+1] ;
00225
00226
00227 string::size_type len = server_name.length() ;
00228 char temp_name[len + 1] ;
00229 server_name.copy( temp_name, len ) ;
00230 temp_name[len] = '\0' ;
00231 arguments[0] = temp_name ;
00232
00233
00234
00235 for( int i = 1; i < num_args; i++ )
00236 {
00237 arguments[i] = argv[i] ;
00238 }
00239 arguments[num_args] = NULL ;
00240
00241 if( !access( file_for_listener.c_str(), F_OK ) )
00242 {
00243 ifstream temp( file_for_listener.c_str() ) ;
00244 cout << NameProgram
00245 << ": there seems to be a BES daemon already running at " ;
00246 char buf[500] ;
00247 temp.getline( buf, 500 ) ;
00248 cout << buf << endl ;
00249 temp.close() ;
00250 return 1 ;
00251 }
00252
00253 daemon_init() ;
00254
00255 int restart = mount_server( arguments ) ;
00256 if( restart == 2 )
00257 {
00258 cout << NameProgram
00259 << ": server cannot mount at first try (core dump). "
00260 << "Please correct problems on the process manager "
00261 << server_name << endl ;
00262 return 0 ;
00263 }
00264 while( restart )
00265 {
00266 sleep( 5 ) ;
00267 restart = mount_server( arguments ) ;
00268 }
00269 delete [] arguments; arguments = 0 ;
00270
00271 if( !access( file_for_listener.c_str(), F_OK ) )
00272 {
00273 (void)remove( file_for_listener.c_str() ) ;
00274 }
00275
00276 return 0 ;
00277 }
00278
00279 int
00280 daemon_init()
00281 {
00282 pid_t pid ;
00283 if( ( pid = fork() ) < 0 )
00284 return -1 ;
00285 else if( pid != 0 )
00286 exit( 0 ) ;
00287 setsid() ;
00288 return 0 ;
00289 }
00290
00291 int
00292 mount_server(char **arguments)
00293 {
00294 const char *perror_string = 0 ;
00295 pid_t pid ;
00296 int status ;
00297 if( ( pid = fork() ) < 0 )
00298 {
00299 cerr << NameProgram << ": fork error " ;
00300 perror_string = strerror( errno ) ;
00301 if( perror_string )
00302 cerr << perror_string ;
00303 cerr << endl ;
00304 return 1 ;
00305 }
00306 else if( pid == 0 )
00307 {
00308 execvp( arguments[0], arguments ) ;
00309 cerr << NameProgram
00310 << ": mounting listener, subprocess failed: " ;
00311 perror_string = strerror( errno ) ;
00312 if( perror_string )
00313 cerr << perror_string ;
00314 cerr << endl ;
00315 exit( 1 ) ;
00316 }
00317 store_listener_id( pid ) ;
00318 if( ( pid = waitpid( pid, &status, 0 ) ) < 0 )
00319 {
00320 cerr << NameProgram << ": waitpid error " ;
00321 perror_string = strerror( errno ) ;
00322 if( perror_string )
00323 cerr << perror_string ;
00324 cerr << endl ;
00325 return 1 ;
00326 }
00327 int child_status = pr_exit( status ) ;
00328 return child_status ;
00329 }
00330
00331 int
00332 pr_exit(int status)
00333 {
00334 if( WIFEXITED( status ) )
00335 {
00336 int status_to_be_returned = SERVER_EXIT_UNDEFINED_STATE ;
00337 switch( WEXITSTATUS( status ) )
00338 {
00339 case SERVER_EXIT_NORMAL_SHUTDOWN:
00340 status_to_be_returned = 0 ;
00341 break ;
00342 case SERVER_EXIT_FATAL_CAN_NOT_START:
00343 {
00344 cerr << NameProgram
00345 << ": server cannot start, exited with status "
00346 << WEXITSTATUS( status ) << endl ;
00347 cerr << "Please check all error messages "
00348 << "and adjust server installation" << endl ;
00349 status_to_be_returned = 0 ;
00350 }
00351 break;
00352 case SERVER_EXIT_ABNORMAL_TERMINATION:
00353 {
00354 cerr << NameProgram
00355 << ": abnormal server termination, exited with status "
00356 << WEXITSTATUS( status ) << endl ;
00357 status_to_be_returned = 1 ;
00358 }
00359 break;
00360 case SERVER_EXIT_RESTART:
00361 {
00362 cout << NameProgram
00363 << ": server has been requested to re-start." << endl ;
00364 status_to_be_returned = 1 ;
00365 }
00366 break;
00367 default:
00368 status_to_be_returned = 1 ;
00369 break;
00370 }
00371
00372 return status_to_be_returned;
00373 }
00374 else if( WIFSIGNALED( status ) )
00375 {
00376 cerr << NameProgram
00377 << ": abnormal server termination, signaled with signal number "
00378 << WTERMSIG( status ) << endl ;
00379 #ifdef WCOREDUMP
00380 if( WCOREDUMP( status ) )
00381 {
00382 cerr << NameProgram << ": server dumped core." << endl ;
00383 return 2 ;
00384 }
00385 #endif
00386 return 1;
00387 }
00388 else if( WIFSTOPPED( status ) )
00389 {
00390 cerr << NameProgram
00391 << ": abnormal server termination, stopped with signal number "
00392 << WSTOPSIG( status ) << endl ;
00393 return 1 ;
00394 }
00395 return 0 ;
00396 }
00397
00398 void
00399 store_listener_id( int pid )
00400 {
00401 const char *perror_string = 0 ;
00402 ofstream f( file_for_listener.c_str() ) ;
00403 if( !f )
00404 {
00405 cerr << NameProgram << ": unable to create pid file "
00406 << file_for_listener << ": " ;
00407 perror_string = strerror( errno ) ;
00408 if( perror_string )
00409 cerr << perror_string ;
00410 cerr << " ... Continuing" << endl ;
00411 cerr << endl ;
00412 }
00413 else
00414 {
00415 f << "PID: " << pid << " UID: " << getuid() << endl ;
00416 f.close() ;
00417 mode_t new_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
00418 (void)chmod( file_for_listener.c_str(), new_mode ) ;
00419 }
00420 }
00421
00422 bool
00423 load_names( const string &install_dir, const string &pid_dir )
00424 {
00425 char *xdap_root = 0 ;
00426 string bindir = "/bin";
00427 if( !pid_dir.empty() )
00428 {
00429 file_for_listener = pid_dir ;
00430 }
00431
00432 if( !install_dir.empty() )
00433 {
00434 server_name = install_dir ;
00435 server_name += bindir ;
00436 if( file_for_listener.empty() )
00437 {
00438 file_for_listener = install_dir + "/var/run" ;
00439 }
00440 }
00441 else
00442 {
00443 string prog = NameProgram ;
00444 string::size_type slash = prog.find_last_of( '/' ) ;
00445 if( slash != string::npos )
00446 {
00447 server_name = prog.substr( 0, slash ) ;
00448 slash = prog.find_last_of( '/' ) ;
00449 if( slash != string::npos )
00450 {
00451 string root = prog.substr( 0, slash ) ;
00452 if( file_for_listener.empty() )
00453 {
00454 file_for_listener = root + "/var/run" ;
00455 }
00456 }
00457 else
00458 {
00459 if( file_for_listener.empty() )
00460 {
00461 file_for_listener = server_name ;
00462 }
00463 }
00464 }
00465 }
00466
00467 if( server_name == "" )
00468 {
00469 server_name = "." ;
00470 if( file_for_listener.empty() )
00471 {
00472 file_for_listener = "./run" ;
00473 }
00474 }
00475
00476 server_name += BES_SERVER ;
00477 file_for_listener += BES_SERVER_PID ;
00478
00479 if( access( server_name.c_str(), F_OK ) != 0 )
00480 {
00481 cerr << NameProgram
00482 << ": cannot start." << server_name << endl
00483 << "Please either pass -i <install_dir> on the command line or "
00484 << "set the environment variable " << BES_SERVER_ROOT << " "
00485 << "to the installation directory where the BES listener is."
00486 << endl ;
00487 return false ;
00488 }
00489 return true ;
00490 }
00491