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 OmniEvents {
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 int priority =LOG_INFO;
00268
00269
00270
00271 const char* mPos( message );
00272 const char* pPos( "omniEvents: " );
00273 while(*mPos && (*mPos==*pPos || *pPos==':'))
00274 {
00275 ++mPos;
00276 ++pPos;
00277 if(!*pPos)
00278 {
00279 switch(message[10])
00280 {
00281 case '!': priority=LOG_ERR;
00282 case ':': message=mPos;
00283 }
00284 break;
00285 }
00286 }
00287
00288 ::syslog(priority,message);
00289 #ifndef LOG_PERROR
00290
00291
00292 if(daemon._haveParent)
00293 cerr<<message<<flush;
00294 #endif
00295 }
00296
00297
00298 void DaemonImpl::checkPidfileOrShutdown()
00299 {
00300 if(!_pidfile)
00301 return;
00302
00303
00304 pid_t pidFromFile =0;
00305 struct stat buf;
00306 if(0==::stat(_pidfile,&buf))
00307 {
00308 if(!S_ISREG(buf.st_mode))
00309 {
00310 cerr<<"Pidfile '"<<_pidfile<<"' is not a regular file."<<endl;
00311 ::exit(-1);
00312 }
00313 try
00314 {
00315 ifstream infile(_pidfile);
00316 infile>>pidFromFile;
00317 infile.close();
00318 }
00319 catch(...)
00320 {
00321 cerr<<"Failed to read pidfile'"<<_pidfile<<"'."<<endl;
00322 ::exit(-1);
00323 }
00324 }
00325 else if(errno!=ENOENT)
00326 {
00327 cerr<<"Failed to stat pidfile '"<<_pidfile<<"': "
00328 <<STRERR_FILE_LINE<<endl;
00329 ::exit(-1);
00330 }
00331
00332
00333 if(pidFromFile>0)
00334 {
00335 if(0==::kill(pidFromFile,0))
00336 {
00337 cerr<<"Quitting because process "<<pidFromFile
00338 <<" defined in pidfile '"<<_pidfile<<"'"
00339 <<" is already running."<<endl;
00340 ::exit(-1);
00341 }
00342 else if(errno!=ESRCH)
00343 {
00344 cerr<<"Failed to test for process "<<pidFromFile
00345 <<" defined in pidfile '"<<_pidfile<<"': "
00346 <<STRERR_FILE_LINE<<endl;
00347 ::exit(-1);
00348 }
00349 }
00350 }
00351
00352
00353 void DaemonImpl::writePidfile()
00354 {
00355 if(_pidfile)
00356 {
00357 try
00358 {
00359 #ifdef FSTREAM_OPEN_PROT
00360 ofstream outfile(_pidfile,ios::out|ios::trunc,0644);
00361 #else
00362 ofstream outfile(_pidfile,ios::out|ios::trunc);
00363 #endif
00364 outfile<<::getpid()<<endl;
00365 outfile.close();
00366
00367 _havePidfile=true;
00368 }
00369 catch(...)
00370 {
00371 cerr<<"Failed to write pidfile '"<<_pidfile<<"'."<<endl;
00372 ::exit(-1);
00373 }
00374 }
00375 }
00376
00377
00378 void DaemonImpl::fork()
00379 {
00380 if( ::pipe(_pipe) <0)
00381 {
00382 cerr<<"Failed to open pipe: "<<STRERR_FILE_LINE<<endl;
00383 ::exit(-1);
00384 }
00385
00386
00387 pid_t pid =::fork();
00388 if(pid<0)
00389 {
00390 cerr<<STRERR_FILE_LINE<<endl;
00391 ::exit(-1);
00392 }
00393 else if(pid>0)
00394 {
00395
00396
00397
00398
00399
00400 if( ::close(_pipe[PIPE_WRITE]) <0)
00401 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00402
00403 ::_exit(waitForChild());
00404 }
00405
00406
00407
00408
00409
00410 _haveParent=true;
00411
00412
00413 if( ::close(_pipe[PIPE_READ]) <0)
00414 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00415
00416
00417 pid_t sid =::setsid();
00418 if(sid<0)
00419 {
00420 cerr<<STRERR_FILE_LINE<<endl;
00421 ::exit(-1);
00422 }
00423 }
00424
00425
00426 void DaemonImpl::redirectStreamsTo(const char* filename)
00427 {
00428 if(openFileFor(STDIN_FILENO,"/dev/null",O_RDONLY)<0)
00429 {
00430 cerr<<"Failed to open /dev/null for STDIN: "<<STRERR_FILE_LINE<<endl;
00431 ::exit(-1);
00432 }
00433 if(openFileFor(STDOUT_FILENO,filename,O_WRONLY|O_CREAT|O_APPEND)<0)
00434 {
00435 cerr<<"Failed to open "<<filename<<" for STDOUT: "<<STRERR_FILE_LINE<<endl;
00436 ::exit(-1);
00437 }
00438 if(openFileFor(STDERR_FILENO,filename,O_WRONLY|O_CREAT|O_APPEND)<0)
00439 {
00440 cerr<<"Failed to open "<<filename<<" for STDERR: "<<STRERR_FILE_LINE<<endl;
00441 ::exit(-1);
00442 }
00443 }
00444
00445
00446 int DaemonImpl::openFileFor(int fd, const char* filename, int flags)
00447 {
00448 int newfd =::open(filename,flags,0644);
00449 if(newfd<0)
00450 return -1;
00451 if(newfd==fd)
00452 return fd;
00453 if(::dup2(newfd,fd)<0)
00454 return -1;
00455 ::close(newfd);
00456 return fd;
00457 }
00458
00459
00460 int DaemonImpl::waitForChild()
00461 {
00462 int status =-1;
00463 ssize_t bytes =::read(_pipe[PIPE_READ],&status,sizeof(status));
00464 if(bytes<sizeof(status))
00465 {
00466 status=-1;
00467 if(bytes<0)
00468 cerr<<"Parent failed to read result from pipe: "<<STRERR_FILE_LINE<<endl;
00469 }
00470 if( ::close(_pipe[PIPE_READ]) !=0)
00471 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00472
00473 return status;
00474 }
00475
00476
00477 void DaemonImpl::notifyParent(int status)
00478 {
00479 ssize_t r =::write(_pipe[PIPE_WRITE],&status,sizeof(status));
00480 if(r<sizeof(status))
00481 {
00482 if(r<0)
00483 cerr<<"read() failed while writing return value to pipe: "
00484 <<STRERR_FILE_LINE<<endl;
00485 else
00486 cerr<<"write() too short while writing return value from pipe: "
00487 <<STRERR_FILE_LINE<<endl;
00488 }
00489 if( ::close(_pipe[PIPE_WRITE]) !=0)
00490 cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
00491 }
00492
00493 }