[Pkg-corba-commits] r269 - /trunk/omnievents/src/daemon_unix.cc
tgg at users.alioth.debian.org
tgg at users.alioth.debian.org
Mon May 2 21:33:03 UTC 2011
Author: tgg
Date: Mon May 2 21:33:00 2011
New Revision: 269
URL: http://svn.debian.org/wsvn/pkg-corba/?sc=1&rev=269
Log:
commit patch from https://bugs.launchpad.net/ubuntu/+source/omnievents/+bug/705020
Added:
trunk/omnievents/src/daemon_unix.cc
Added: trunk/omnievents/src/daemon_unix.cc
URL: http://svn.debian.org/wsvn/pkg-corba/trunk/omnievents/src/daemon_unix.cc?rev=269&op=file
==============================================================================
--- trunk/omnievents/src/daemon_unix.cc (added)
+++ trunk/omnievents/src/daemon_unix.cc Mon May 2 21:33:00 2011
@@ -1,0 +1,493 @@
+// Package : omniEvents
+// daemon_unix.h Created : 2004/06/29
+// Author : Alex Tingle
+//
+// Copyright (C) 2004 Alex Tingle.
+//
+// This file is part of the omniEvents application.
+//
+// omniEvents is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// omniEvents is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#include "daemon.h"
+#include "main.h"
+#include "daemon_unix.h"
+
+#define NEED_PACKAGE_INFO
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_IOSTREAM
+# include <iostream>
+# include <fstream>
+#else
+# include <iostream.h>
+# include <fstream.h>
+#endif
+
+#ifdef HAVE_STD_IOSTREAM
+using namespace std;
+#endif
+
+#include <stdlib.h> // exit, on_exit
+#include <errno.h> // errno
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // fork, umask, setsid, dup2, chdir, close
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> // fork, umask, open
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h> //open
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h> // open
+#endif
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h> // openlog, syslog
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h> // strerror
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h> // kill
+#endif
+
+#include <string>
+
+// Forward declaration of omniORB::setLogFunction()
+namespace omniORB {
+ void setLogFunction(void (*logFunction)(const char*));
+}
+
+namespace OmniEvents {
+
+#define STRERR_FILE_LINE strerror(errno)<<" "<<__FILE__<<":"<<__LINE__
+
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+//////////////////////////////////////////////////////////////////////////////
+
+/** Singleton - only at file scope. Although we initialize the value to NULL,
+ * we don't trust that the runtime will actually initialise it.
+ */
+DaemonImpl daemon;
+
+Daemon::Daemon(int&,char**&)
+{
+ // Initialise the DaemonImpl singleton.
+ daemon._tracefile=NULL;
+ daemon._foreground=false;
+ daemon._pidfile=NULL;
+ daemon._pipe[0]=daemon._pipe[1]=-1;
+ daemon._havePidfile=false;
+ daemon._haveParent=false;
+ daemon._haveSyslog=false;
+}
+void Daemon::tracefile(const char* val) { daemon.tracefile(val); }
+void Daemon::pidfile(const char* val) { daemon.pidfile(val); }
+void Daemon::foreground(bool val) { daemon.foreground(val); }
+void Daemon::daemonize() { daemon.daemonize(); }
+void Daemon::runningOk() { daemon.runningOk(); }
+Daemon::~Daemon() { daemon.shutdown(0); }
+
+void shutdown0(void) { daemon.shutdown(0); } ///< Param to atexit().
+void shutdown2(int s,void*){ daemon.shutdown(s); } ///< Param to on_exit().
+
+//////////////////////////////////////////////////////////////////////////////
+
+DaemonImpl::DaemonImpl(){}
+
+
+DaemonImpl::~DaemonImpl()
+{
+ delete[] _pidfile;
+ delete[] _tracefile;
+ _pidfile=NULL;
+ _tracefile=NULL;
+}
+
+
+void DaemonImpl::tracefile(const char* val)
+{
+ _tracefile=::strdup(val);
+}
+
+
+void DaemonImpl::foreground(bool val)
+{
+ _foreground=val;
+}
+
+
+void DaemonImpl::pidfile(const char* val)
+{
+ string pidfileStr =val;
+ if(pidfileStr[0]!='/')
+ pidfileStr=string("/var/run/")+pidfileStr;
+ DaemonImpl::_pidfile=::strdup(pidfileStr.c_str());
+}
+
+
+void DaemonImpl::initialize(int&,char**&)
+{
+ // Does nothing on Unix
+}
+
+
+void DaemonImpl::daemonize()
+{
+ // Register the shutdown function.
+#ifdef HAVE_ON_EXIT
+ if( ::on_exit(shutdown2,NULL) <0)
+#else
+ if( ::atexit(shutdown0) <0)
+#endif
+ {
+ cerr<<"Failed to set exit handler."<<endl;
+ ::exit(-1);
+ }
+
+ if(!_foreground)
+ {
+ this->fork();
+ // ...now in the CHILD.
+ }
+
+ // Check & write the pidfile (if _pidfile is set).
+ checkPidfileOrShutdown();
+ writePidfile();
+
+ // Change the file mode mask
+ ::umask(0);
+
+ // Change the current working directory
+ if(::chdir("/")!=0)
+ {
+ cerr<<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+
+ // If _tracefile is not set, then use syslog.
+ if(_tracefile && _tracefile[0]!='\0')
+ {
+ redirectStreamsTo(_tracefile);
+ }
+ else
+ {
+#ifndef HAVE_OMNIORB3
+# ifdef LOG_PERROR
+ ::openlog(PACKAGE_NAME ": ",LOG_PID|LOG_PERROR,LOG_DAEMON);
+# else
+ ::openlog(PACKAGE_NAME ": ",LOG_PID,LOG_DAEMON);
+# endif
+ _haveSyslog=true;
+ omniORB::setLogFunction(DaemonImpl::log);
+#else
+ cerr<<"You must use option -t to set the file for trace messages."
+ "\n(This is because omniORB3 cannot redirect messages to syslog.)"<<endl;
+ ::exit(-1);
+#endif
+ }
+} // end daemonize()
+
+
+void DaemonImpl::runningOk()
+{
+ if(_haveParent)
+ {
+ _haveParent=false;
+ notifyParent(0);
+ }
+
+ // No longer send syslog messages to stderr.
+ if(_haveSyslog)
+ {
+#ifdef LOG_PERROR
+ ::closelog();
+ // FIXME: Possible race here? If a log message is sent right now.
+ ::openlog(PACKAGE_NAME ": ",LOG_PID,LOG_DAEMON);
+#endif
+ redirectStreamsTo("/dev/null");
+ }
+}
+
+
+void DaemonImpl::shutdown(int status)
+{
+ // Remove the pidfile.
+ if(_havePidfile && _pidfile && 0!=::unlink(_pidfile))
+ {
+ cerr<<"Failed to remove pidfile '"<<_pidfile<<"': "
+ <<STRERR_FILE_LINE<<endl;
+ status=-1;
+ }
+ _havePidfile=false;
+
+ // Close syslog.
+ if(_haveSyslog)
+ {
+ _haveSyslog=false;
+ ::closelog();
+ }
+
+ // Notify the parent.
+ if(_haveParent)
+ {
+ _haveParent=false;
+ notifyParent(status);
+ }
+
+ // outtahere...
+}
+
+
+void DaemonImpl::log(const char* message)
+{
+ int priority =LOG_INFO;
+ // Cut off the redundant package name prefix.
+ // "omniEvents: " --> stripped off
+ // "omniEvents! " --> stripped off and sets priority to LOG_ERR
+ const char* mPos( message );
+ const char* pPos( "omniEvents: " );
+ while(*mPos && (*mPos==*pPos || *pPos==':'))
+ {
+ ++mPos;
+ ++pPos;
+ if(!*pPos)
+ {
+ switch(message[10])
+ {
+ case '!': priority=LOG_ERR; // ...AND DROPS THROUGH...
+ case ':': message=mPos;
+ }
+ break; // loop exit
+ }
+ }
+ // Send the message.
+ ::syslog(priority,"%s",message);
+#ifndef LOG_PERROR
+ // If we don't have LOG_PERROR, then we'll have to manually send
+ // log messages to stderr.
+ if(daemon._haveParent)
+ cerr<<message<<flush;
+#endif
+}
+
+
+void DaemonImpl::checkPidfileOrShutdown()
+{
+ if(!_pidfile)
+ return;
+
+ // Try to read pidfile.
+ pid_t pidFromFile =0;
+ struct stat buf;
+ if(0==::stat(_pidfile,&buf))
+ {
+ if(!S_ISREG(buf.st_mode))
+ {
+ cerr<<"Pidfile '"<<_pidfile<<"' is not a regular file."<<endl;
+ ::exit(-1);
+ }
+ try
+ {
+ ifstream infile(_pidfile);
+ infile>>pidFromFile;
+ infile.close();
+ }
+ catch(...)
+ {
+ cerr<<"Failed to read pidfile'"<<_pidfile<<"'."<<endl;
+ ::exit(-1);
+ }
+ }
+ else if(errno!=ENOENT)
+ {
+ cerr<<"Failed to stat pidfile '"<<_pidfile<<"': "
+ <<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+
+ // If process 'pidFromFile' is running then exit, else remove pidfile.
+ if(pidFromFile>0)
+ {
+ if(0==::kill(pidFromFile,0)) // tests for running 'pidFromFile'.
+ {
+ cerr<<"Quitting because process "<<pidFromFile
+ <<" defined in pidfile '"<<_pidfile<<"'"
+ <<" is already running."<<endl;
+ ::exit(-1);
+ }
+ else if(errno!=ESRCH)
+ {
+ cerr<<"Failed to test for process "<<pidFromFile
+ <<" defined in pidfile '"<<_pidfile<<"': "
+ <<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+ }
+}
+
+
+void DaemonImpl::writePidfile()
+{
+ if(_pidfile)
+ {
+ try
+ {
+#ifdef FSTREAM_OPEN_PROT
+ ofstream outfile(_pidfile,ios::out|ios::trunc,0644);
+#else
+ ofstream outfile(_pidfile,ios::out|ios::trunc);
+#endif
+ outfile<<::getpid()<<endl;
+ outfile.close();
+ // Tell shutdown() that the pidfile needs to be cleared away.
+ _havePidfile=true;
+ }
+ catch(...)
+ {
+ cerr<<"Failed to write pidfile '"<<_pidfile<<"'."<<endl;
+ ::exit(-1);
+ }
+ }
+}
+
+
+void DaemonImpl::fork()
+{
+ if( ::pipe(_pipe) <0)
+ {
+ cerr<<"Failed to open pipe: "<<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+
+ // Fork off from the parent process
+ pid_t pid =::fork();
+ if(pid<0)
+ {
+ cerr<<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+ else if(pid>0)
+ {
+ //
+ // Now in the PARENT
+ //
+
+ // Close the write end of the pipe.
+ if( ::close(_pipe[PIPE_WRITE]) <0)
+ cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
+
+ ::_exit(waitForChild()); // Exit without flushing buffers
+ }
+
+ //
+ // ...now in the CHILD.
+ //
+
+ _haveParent=true;
+
+ // Close the read end of the pipe
+ if( ::close(_pipe[PIPE_READ]) <0)
+ cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
+
+ // Create a new SID for the child process
+ pid_t sid =::setsid();
+ if(sid<0)
+ {
+ cerr<<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+}
+
+
+void DaemonImpl::redirectStreamsTo(const char* filename)
+{
+ if(openFileFor(STDIN_FILENO,"/dev/null",O_RDONLY)<0)
+ {
+ cerr<<"Failed to open /dev/null for STDIN: "<<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+ if(openFileFor(STDOUT_FILENO,filename,O_WRONLY|O_CREAT|O_APPEND)<0)
+ {
+ cerr<<"Failed to open "<<filename<<" for STDOUT: "<<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+ if(openFileFor(STDERR_FILENO,filename,O_WRONLY|O_CREAT|O_APPEND)<0)
+ {
+ cerr<<"Failed to open "<<filename<<" for STDERR: "<<STRERR_FILE_LINE<<endl;
+ ::exit(-1);
+ }
+}
+
+
+int DaemonImpl::openFileFor(int fd, const char* filename, int flags)
+{
+ int newfd =::open(filename,flags,0644);
+ if(newfd<0)
+ return -1;
+ if(newfd==fd)
+ return fd;
+ if(::dup2(newfd,fd)<0) // replace fd with a copy of newfd
+ return -1;
+ ::close(newfd);
+ return fd;
+}
+
+
+int DaemonImpl::waitForChild()
+{
+ int status =-1;
+ ssize_t bytes =::read(_pipe[PIPE_READ],&status,sizeof(status));
+ if(bytes<sizeof(status))
+ {
+ status=-1;
+ if(bytes<0)
+ cerr<<"Parent failed to read result from pipe: "<<STRERR_FILE_LINE<<endl;
+ }
+ if( ::close(_pipe[PIPE_READ]) !=0)
+ cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
+
+ return status;
+}
+
+
+void DaemonImpl::notifyParent(int status)
+{
+ ssize_t r =::write(_pipe[PIPE_WRITE],&status,sizeof(status));
+ if(r<sizeof(status))
+ {
+ if(r<0)
+ cerr<<"read() failed while writing return value to pipe: "
+ <<STRERR_FILE_LINE<<endl;
+ else
+ cerr<<"write() too short while writing return value from pipe: "
+ <<STRERR_FILE_LINE<<endl;
+ }
+ if( ::close(_pipe[PIPE_WRITE]) !=0)
+ cerr<<"Failed to close pipe: "<<STRERR_FILE_LINE<<endl;
+}
+
+} // end namespace OmniEvents
More information about the Pkg-corba-commits
mailing list