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