00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "daemon.h"
00025 #include "main.h"
00026 #include "daemon_unix.h"
00027
00028 #define NEED_PACKAGE_INFO
00029 #ifdef HAVE_CONFIG_H
00030 # include "config.h"
00031 #endif
00032
00033 #ifdef HAVE_IOSTREAM
00034 # include <iostream>
00035 # include <fstream>
00036 #else
00037 # include <iostream.h>
00038 # include <fstream.h>
00039 #endif
00040
00041 #ifdef HAVE_STD_IOSTREAM
00042 using namespace std;
00043 #endif
00044
00045 #include <stdlib.h>
00046 #include <errno.h>
00047
00048 #ifdef HAVE_UNISTD_H
00049 # include <unistd.h>
00050 #endif
00051
00052 #ifdef HAVE_SYS_TYPES_H
00053 # include <sys/types.h>
00054 #endif
00055
00056 #ifdef HAVE_SYS_STAT_H
00057 # include <sys/stat.h>
00058 #endif
00059
00060 #ifdef HAVE_FCNTL_H
00061 # include <fcntl.h>
00062 #endif
00063
00064 #ifdef HAVE_SYSLOG_H
00065 # include <syslog.h>
00066 #endif
00067
00068 #ifdef HAVE_STRING_H
00069 # include <string.h>
00070 #endif
00071
00072 #ifdef HAVE_SIGNAL_H
00073 #include <signal.h>
00074 #endif
00075
00076 #include <string>
00077
00078
00079 namespace omniORB {
00080 void setLogFunction(void (*logFunction)(const char*));
00081 }
00082
00083 namespace Omniifr {
00084
00085 #define STRERR_FILE_LINE strerror(errno)<<" "<<__FILE__<<":"<<__LINE__
00086
00087 #define PIPE_READ 0
00088 #define PIPE_WRITE 1
00089
00090
00094 DaemonImpl daemon;
00095
00096 Daemon::Daemon(int&,char**&)
00097 {
00098
00099 daemon._tracefile=NULL;
00100 daemon._foreground=false;
00101 daemon._pidfile=NULL;
00102 daemon._pipe[0]=daemon._pipe[1]=-1;
00103 daemon._havePidfile=false;
00104 daemon._haveParent=false;
00105 daemon._haveSyslog=false;
00106 }
00107 void Daemon::tracefile(const char* val) { daemon.tracefile(val); }
00108 void Daemon::pidfile(const char* val) { daemon.pidfile(val); }
00109 void Daemon::foreground(bool val) { daemon.foreground(val); }
00110 void Daemon::daemonize() { daemon.daemonize(); }
00111 void Daemon::runningOk() { daemon.runningOk(); }
00112 Daemon::~Daemon() { daemon.shutdown(0); }
00113
00114 void shutdown0(void) { daemon.shutdown(0); }
00115 void shutdown2(int s,void*){ daemon.shutdown(s); }
00116
00118
00119 DaemonImpl::DaemonImpl(){}
00120
00121
00122 DaemonImpl::~DaemonImpl()
00123 {
00124 delete[] _pidfile;
00125 delete[] _tracefile;
00126 _pidfile=NULL;
00127 _tracefile=NULL;
00128 }
00129
00130
00131 void DaemonImpl::tracefile(const char* val)
00132 {
00133 _tracefile=::strdup(val);
00134 }
00135
00136
00137 void DaemonImpl::foreground(bool val)
00138 {
00139 _foreground=val;
00140 }
00141
00142
00143 void DaemonImpl::pidfile(const char* val)
00144 {
00145 string pidfileStr =val;
00146 if(pidfileStr[0]!='/')
00147 pidfileStr=string("/var/run/")+pidfileStr;
00148 DaemonImpl::_pidfile=::strdup(pidfileStr.c_str());
00149 }
00150
00151
00152 void DaemonImpl::initialize(int&,char**&)
00153 {
00154
00155 }
00156
00157
00158 void DaemonImpl::daemonize()
00159 {
00160
00161 #ifdef HAVE_ON_EXIT
00162 if( ::on_exit(shutdown2,NULL) <0)
00163 #else
00164 if( ::atexit(shutdown0) <0)
00165 #endif
00166 {
00167 cerr<<"Failed to set exit handler."<<endl;
00168 ::exit(-1);
00169 }
00170
00171 if(!_foreground)
00172 {
00173 this->fork();
00174
00175 }
00176
00177
00178 checkPidfileOrShutdown();
00179 writePidfile();
00180
00181
00182 ::umask(0);
00183
00184
00185 if(::chdir("/")!=0)
00186 {
00187 cerr<<STRERR_FILE_LINE<<endl;
00188 ::exit(-1);
00189 }
00190
00191
00192 if(_tracefile && _tracefile[0]!='\0')
00193 {
00194 redirectStreamsTo(_tracefile);
00195 }
00196 else
00197 {
00198 #ifndef HAVE_OMNIORB3
00199 # ifdef LOG_PERROR
00200 ::openlog(PACKAGE_NAME ": ",LOG_PID|LOG_PERROR,LOG_DAEMON);
00201 # else
00202 ::openlog(PACKAGE_NAME ": ",LOG_PID,LOG_DAEMON);
00203 # endif
00204 _haveSyslog=true;
00205 omniORB::setLogFunction(DaemonImpl::log);
00206 #else
00207 cerr<<"You must use option -t to set the file for trace messages."
00208 "\n(This is because omniORB3 cannot redirect messages to syslog.)"<<endl;
00209 ::exit(-1);
00210 #endif
00211 }
00212 }
00213
00214
00215 void DaemonImpl::runningOk()
00216 {
00217 if(_haveParent)
00218 {
00219 _haveParent=false;
00220 notifyParent(0);
00221 }
00222
00223
00224 if(_haveSyslog)
00225 {
00226 #ifdef LOG_PERROR
00227 ::closelog();
00228
00229 ::openlog(PACKAGE_NAME ": ",LOG_PID,LOG_DAEMON);
00230 #endif
00231 redirectStreamsTo("/dev/null");
00232 }
00233 }
00234
00235
00236 void DaemonImpl::shutdown(int status)
00237 {
00238
00239 if(_havePidfile && _pidfile && 0!=::unlink(_pidfile))
00240 {
00241 cerr<<"Failed to remove pidfile '"<<_pidfile<<"': "
00242 <<STRERR_FILE_LINE<<endl;
00243 status=-1;
00244 }
00245 _havePidfile=false;
00246
00247
00248 if(_haveSyslog)
00249 {
00250 _haveSyslog=false;
00251 ::closelog();
00252 }
00253
00254
00255 if(_haveParent)
00256 {
00257 _haveParent=false;
00258 notifyParent(status);
00259 }
00260
00261
00262 }
00263
00264
00265 void DaemonImpl::log(const char* message)
00266 {
00267
00268 static const char* packageNamePrefix ="omniIFR: ";
00269 static const size_t packageNamePrefixLen =::strlen(packageNamePrefix);
00270 if(0==::strncmp(message,packageNamePrefix,packageNamePrefixLen))
00271 message+=packageNamePrefixLen;
00272
00273 ::syslog(LOG_INFO,message);
00274 #ifndef LOG_PERROR
00275
00276
00277 if(daemon._haveParent)
00278 cerr<<message<<flush;
00279 #endif
00280 }
00281
00282
00283 void DaemonImpl::checkPidfileOrShutdown()
00284 {
00285 if(!_pidfile)
00286 return;
00287
00288
00289 pid_t pidFromFile =0;
00290 struct stat buf;
00291 if(0==::stat(_pidfile,&buf))
00292 {
00293 if(!S_ISREG(buf.st_mode))
00294 {
00295 cerr<<"Pidfile '"<<_pidfile<<"' is not a regular file."<<endl;
00296 ::exit(-1);
00297 }
00298 try
00299 {
00300 ifstream infile(_pidfile);
00301 infile>>pidFromFile;
00302 infile.close();
00303 }
00304 catch(...)
00305 {
00306 cerr<<"Failed to read pidfile'"<<_pidfile<<"'."<<endl;
00307 ::exit(-1);
00308 }
00309 }
00310 else if(errno!=ENOENT)
00311 {
00312 cerr<<"Failed to stat pidfile '"<<_pidfile<<"': "
00313 <<STRERR_FILE_LINE<<endl;
00314 ::exit(-1);
00315 }
00316
00317
00318 if(pidFromFile>0)
00319 {
00320 if(0==::kill(pidFromFile,0))
00321 {
00322 cerr<<"Quitting because process "<<pidFromFile
00323 <<" defined in pidfile '"<<_pidfile<<"'"
00324 <<" is already running."<<endl;
00325 ::exit(-1);
00326 }
00327 else if(errno!=ESRCH)
00328 {
00329 cerr<<"Failed to test for process "<<pidFromFile
00330 <<" defined in pidfile '"<<_pidfile<<"': "
00331 <<STRERR_FILE_LINE<<endl;
00332 ::exit(-1);
00333 }
00334 }
00335 }
00336
00337
00338 void DaemonImpl::writePidfile()
00339 {
00340 if(_pidfile)
00341 {
00342 try
00343 {
00344 #ifdef FSTREAM_OPEN_PROT
00345 ofstream outfile(_pidfile,ios::out|ios::trunc,0644);
00346 #else
00347 ofstream outfile(_pidfile,ios::out|ios::trunc);
00348 #endif
00349 outfile<<::getpid()<<endl;
00350 outfile.close();
00351
00352 _havePidfile=true;
00353 }
00354 catch(...)
00355 {
00356 cerr<<"Failed to write pidfile '"<<_pidfile<<"'."<<endl;
00357 ::exit(-1);
00358 }
00359 }
00360 }
00361
00362
00363 void DaemonImpl::fork()
00364 {
00365 if( ::pipe(_pipe) <0)
00366 {
00367 cerr<<"Failed to open pipe: "<<STRERR_FILE_LINE<<endl;
00368 ::exit(-1);
00369 }
00370
00371
00372 pid_t pid =::fork();
00373 if(pid<0)
00374 {
00375 cerr<<STRERR_FILE_LINE<<endl;
00376 ::exit(-1);
00377 }
00378 else if(pid>0)
00379 {
00380
00381
00382
00383
00384
00385 if( ::close(_pipe[PIPE_WRITE]) <0)
00386 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00387
00388 ::_exit(waitForChild());
00389 }
00390
00391
00392
00393
00394
00395 _haveParent=true;
00396
00397
00398 if( ::close(_pipe[PIPE_READ]) <0)
00399 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00400
00401
00402 pid_t sid =::setsid();
00403 if(sid<0)
00404 {
00405 cerr<<STRERR_FILE_LINE<<endl;
00406 ::exit(-1);
00407 }
00408 }
00409
00410
00411 void DaemonImpl::redirectStreamsTo(const char* filename)
00412 {
00413 if(openFileFor(STDIN_FILENO,"/dev/null",O_RDONLY)<0)
00414 {
00415 cerr<<"Failed to open /dev/null for STDIN: "<<STRERR_FILE_LINE<<endl;
00416 ::exit(-1);
00417 }
00418 if(openFileFor(STDOUT_FILENO,filename,O_WRONLY|O_CREAT|O_APPEND)<0)
00419 {
00420 cerr<<"Failed to open "<<filename<<" for STDOUT: "<<STRERR_FILE_LINE<<endl;
00421 ::exit(-1);
00422 }
00423 if(openFileFor(STDERR_FILENO,filename,O_WRONLY|O_CREAT|O_APPEND)<0)
00424 {
00425 cerr<<"Failed to open "<<filename<<" for STDERR: "<<STRERR_FILE_LINE<<endl;
00426 ::exit(-1);
00427 }
00428 }
00429
00430
00431 int DaemonImpl::openFileFor(int fd, const char* filename, int flags)
00432 {
00433 int newfd =::open(filename,flags,0644);
00434 if(newfd<0)
00435 return -1;
00436 if(newfd==fd)
00437 return fd;
00438 if(::dup2(newfd,fd)<0)
00439 return -1;
00440 ::close(newfd);
00441 return fd;
00442 }
00443
00444
00445 int DaemonImpl::waitForChild()
00446 {
00447 int status =-1;
00448 ssize_t bytes =::read(_pipe[PIPE_READ],&status,sizeof(status));
00449 if(bytes<sizeof(status))
00450 {
00451 status=-1;
00452 if(bytes<0)
00453 cerr<<"Parent failed to read result from pipe: "<<STRERR_FILE_LINE<<endl;
00454 }
00455 if( ::close(_pipe[PIPE_READ]) !=0)
00456 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00457
00458 return status;
00459 }
00460
00461
00462 void DaemonImpl::notifyParent(int status)
00463 {
00464 ssize_t r =::write(_pipe[PIPE_WRITE],&status,sizeof(status));
00465 if(r<sizeof(status))
00466 {
00467 if(r<0)
00468 cerr<<"read() failed while writing return value to pipe: "
00469 <<STRERR_FILE_LINE<<endl;
00470 else
00471 cerr<<"write() too short while writing return value from pipe: "
00472 <<STRERR_FILE_LINE<<endl;
00473 }
00474 if( ::close(_pipe[PIPE_WRITE]) !=0)
00475 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00476 }
00477
00478 }