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