daemon.cc

Go to the documentation of this file.
00001 // daemon.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,2005 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 Atmostpheric 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 <stdlib.h>
00034 #include <unistd.h>
00035 #include <string.h>
00036 #include <sys/wait.h>
00037 #include <stdio.h>
00038 #include <errno.h>
00039 
00040 #include <fstream>
00041 #include <iostream>
00042 #include <string>
00043 
00044 using std::ifstream ;
00045 using std::ofstream ;
00046 using std::cout ;
00047 using std::endl ;
00048 using std::cerr ;
00049 using std::flush;
00050 using std::string ;
00051 
00052 #include "config.h"
00053 #include "ServerExitConditions.h"
00054 #include "BESServerUtils.h"
00055 
00056 #define BES_SERVER_ROOT "BES_SERVER_ROOT"
00057 #define BES_SERVER "/beslistener"
00058 #define BES_SERVER_PID "bes.pid"
00059 
00060 int  daemon_init() ;
00061 int  mount_server( char ** ) ;
00062 int  pr_exit( int status ) ;
00063 void store_listener_id( int pid ) ;
00064 bool load_names() ;
00065 
00066 string NameProgram ;
00067 
00068 // This two variables are set by load_names
00069 string server_name ;
00070 string file_for_listener ;
00071 
00072 char **arguments = 0 ; 
00073 
00074 int
00075 main(int argc, char *argv[])
00076 {
00077     NameProgram = argv[0] ;
00078 
00079     // Set the name of the listener and the file for the listenet pid
00080     if( !load_names() )
00081         return 1 ;
00082 
00083     arguments = new char *[argc+1] ;
00084 
00085     // Set arguments[0] to the name of the listener
00086     char temp_name[1024] ;
00087     strcpy( temp_name, server_name.c_str() ) ;
00088     arguments[0] = temp_name ;
00089 
00090     // Marshal the arguments to the listener from the command line 
00091     // arguments to the daemon
00092     for( int i = 1; i < argc; i++ )
00093     {
00094         arguments[i] = argv[i] ;
00095     }
00096     arguments[argc] = NULL ;
00097 
00098     // If you change the getopt statement below, be sure to make the
00099     // corresponding change in ServerApp.cc
00100     int c = 0 ;
00101     while( ( c = getopt( argc, argv, "hvsd:c:p:u:" ) ) != EOF )
00102     {
00103         switch( c )
00104         {
00105             case 'v':
00106                 BESServerUtils::show_version( NameProgram ) ;
00107                 break ;
00108             case '?':
00109             case 'h':
00110                 BESServerUtils::show_usage( NameProgram ) ;
00111                 break ;
00112             default:
00113                 break ;
00114         }
00115     }
00116 
00117     if( !access( file_for_listener.c_str(), F_OK ) )
00118     {
00119         ifstream temp( file_for_listener.c_str() ) ;
00120         cout << NameProgram
00121              << ": there seems to be a BES daemon already running at " ;
00122         char buf[500] ;
00123         temp.getline( buf, 500 ) ;
00124         cout << buf << endl ;
00125         temp.close() ;
00126         return 1 ;
00127     }
00128 
00129     daemon_init() ;
00130 
00131     int restart = mount_server( arguments ) ;
00132     if( restart == 2 )
00133     {
00134         cout << NameProgram
00135              << ": server can not mount at first try (core dump). "
00136              << "Please correct problems on the process manager "
00137              << server_name << endl ;
00138         return 0 ;
00139     }
00140     while( restart )
00141     {
00142         sleep( 5 ) ;
00143         restart = mount_server( arguments ) ;
00144     }
00145     delete [] arguments; arguments = 0 ;
00146 
00147     if( !access( file_for_listener.c_str(), F_OK ) )
00148     {
00149         remove( file_for_listener.c_str() ) ;
00150     }
00151 
00152     return 0 ;
00153 }
00154 
00155 int
00156 daemon_init()
00157 {
00158     pid_t pid ;
00159     if( ( pid = fork() ) < 0 )
00160         return -1 ;
00161     else if( pid != 0 )
00162         exit( 0 ) ;
00163     setsid() ;
00164     return 0 ;
00165 }
00166 
00167 int
00168 mount_server(char* *arguments)
00169 {
00170     const char *perror_string = 0 ;
00171     pid_t pid ;
00172     int status ;
00173     if( ( pid = fork() ) < 0 )
00174     {
00175         cerr << NameProgram << ": fork error " ;
00176         perror_string = strerror( errno ) ;
00177         if( perror_string )
00178             cerr << perror_string ;
00179         cerr << endl ;
00180         return 1 ;
00181     }
00182     else if( pid == 0 ) /* child process */
00183     {
00184         execvp( arguments[0], arguments ) ;
00185         cerr << NameProgram
00186              << ": mounting listener, subprocess failed: " ;
00187         perror_string = strerror( errno ) ;
00188         if( perror_string )
00189             cerr << perror_string ;
00190         cerr << endl ;
00191         exit( 1 ) ;
00192     }
00193     store_listener_id( pid ) ;
00194     if( ( pid = waitpid( pid, &status, 0 ) ) < 0 ) /* parent process */
00195     {
00196         cerr << NameProgram << ": waitpid error " ;
00197         perror_string = strerror( errno ) ;
00198         if( perror_string )
00199             cerr << perror_string ;
00200         cerr << endl ;
00201         return 1 ;
00202     }
00203     int child_status = pr_exit( status ) ;
00204     return child_status ;
00205 }
00206 
00207 int
00208 pr_exit(int status)
00209 {
00210     if( WIFEXITED( status ) )
00211     {
00212         int status_to_be_returned = SERVER_EXIT_UNDEFINED_STATE ;
00213         switch( WEXITSTATUS( status ) )
00214         {
00215             case SERVER_EXIT_NORMAL_SHUTDOWN:
00216                 status_to_be_returned = 0 ;
00217                 break ;
00218             case SERVER_EXIT_FATAL_CAN_NOT_START:
00219                 {
00220                     cerr << NameProgram
00221                          << ": server can not start, exited with status "
00222                          << WEXITSTATUS( status ) << endl ;
00223                     cerr << "Please check all error messages "
00224                          << "and adjust server installation" << endl ;
00225                     status_to_be_returned = 0 ;
00226                 }
00227                 break;
00228             case SERVER_EXIT_ABNORMAL_TERMINATION:
00229                 {
00230                     cerr << NameProgram
00231                          << ": abnormal server termination, exited with status "
00232                          << WEXITSTATUS( status ) << endl ;
00233                     status_to_be_returned = 1 ;
00234                 }
00235                 break;
00236             case SERVER_EXIT_RESTART:
00237                 {
00238                     cout << NameProgram
00239                          << ": server has been requested to re-start." << endl ;
00240                     status_to_be_returned = 1 ;
00241                 }
00242                 break;
00243             default:
00244                 status_to_be_returned = 1 ;
00245                 break;
00246         }
00247 
00248         return status_to_be_returned;
00249     }
00250     else if( WIFSIGNALED( status ) )
00251     {
00252         cerr << NameProgram
00253              << ": abnormal server termination, signaled with signal number "
00254              << WTERMSIG( status ) << endl ;
00255 #ifdef WCOREDUMP
00256         if( WCOREDUMP( status ) ) 
00257         {
00258             cerr << NameProgram << ": server dumped core." << endl ;
00259             return 2 ;
00260         }
00261 #endif
00262         return 1;
00263     }
00264     else if( WIFSTOPPED( status ) )
00265     {
00266         cerr << NameProgram
00267              << ": abnormal server termination, stopped with signal number "
00268              << WSTOPSIG( status ) << endl ;
00269         return 1 ;
00270     }
00271     return 0 ;
00272 }
00273 
00274 void
00275 store_listener_id( int pid )
00276 {
00277     const char *perror_string = 0 ;
00278     ofstream f( file_for_listener.c_str() ) ;
00279     if( !f )
00280     {
00281         cerr << NameProgram << ": unable to create pid file "
00282              << file_for_listener << ": " ;
00283         perror_string = strerror( errno ) ;
00284         if( perror_string )
00285             cerr << perror_string ;
00286         cerr << " ... Continuing" << endl ;
00287         cerr << endl ;
00288     }
00289     else
00290     {
00291         f << "PID: " << pid << " UID: " << getuid() << endl ;
00292         f.close() ;
00293     }
00294 }
00295 
00296 bool
00297 load_names()
00298 {
00299     char *xdap_root = 0 ;
00300     string bindir = "/bin";
00301     xdap_root = getenv( BES_SERVER_ROOT ) ;
00302     if( xdap_root )
00303     {
00304         server_name = xdap_root ;
00305         server_name += bindir ;
00306         file_for_listener = xdap_root ;
00307     }
00308     else
00309     {
00310         // BES_SERVER_ROOT is not set, attemp to obtain current
00311         // working directory
00312         /*
00313         char t_buf[1024] ;
00314         if( getcwd( t_buf, sizeof( t_buf ) ) )
00315         {
00316             cout << NameProgram << ": using current working directory "
00317                  << t_buf << endl ;
00318             server_name = t_buf ;
00319             file_for_listener = t_buf ;
00320         }
00321         */
00322         server_name = BES_BIN_DIR ;
00323         file_for_listener = BES_STATE_DIR ;
00324     }
00325     if( server_name == "" )
00326     {
00327         server_name = "." ;
00328         server_name += bindir ;
00329         file_for_listener = "." ;
00330     }
00331 
00332     server_name += BES_SERVER ;
00333     file_for_listener += "/run/" ;
00334     file_for_listener += BES_SERVER_PID ;
00335 
00336     if( access( server_name.c_str(), F_OK ) != 0 )
00337     {
00338         cerr << NameProgram
00339              << ": can not start." << server_name << endl
00340              << "Please set environment variable "
00341              << BES_SERVER_ROOT << " to the location of your listener "
00342              << endl ;
00343         return false ;
00344     }
00345     return true ;
00346 }
00347 

Generated on Wed Aug 29 03:14:16 2007 for OPeNDAP Back End Server (BES) by  doxygen 1.5.2