/* * * Copyright (c) 2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "QpidError.h" #include "Daemon.h" #include #include #include #include #include #include #include namespace qpid { namespace broker { using namespace std; string Daemon::pidFile; string Daemon::name; string Daemon::nameFromArgv0(const char* argv0) { return string(daemon_ident_from_argv0(const_cast(argv0))); } const char* Daemon::getPidFile() { if (pidFile.empty()) { const char* home=getenv("HOME"); if (!home) throw(Exception("$HOME is not set, cant create $HOME/.qpidd.")); using namespace boost::filesystem; path dir = path(home,native) / path(".qpidd", native); create_directory(dir); dir /= name; pidFile = dir.string(); } return pidFile.c_str(); } Daemon::Daemon(const string& name_, int secs) : timeout(secs) { name = name_; daemon_pid_file_ident = daemon_log_ident = name.c_str(); if (getuid() != 0) { // For normal users put pid file under $HOME/.qpid daemon_pid_file_proc = getPidFile; } // For root use the libdaemon default: /var/run. } Daemon::~Daemon() { if (isChild()) daemon_pid_file_remove(); } class Daemon::Retval { public: Retval(); ~Retval(); int send(int s); int wait(int timeout); private: bool completed; }; pid_t Daemon::fork() { retval.reset(new Retval()); pid = daemon_fork(); if (pid < 0) throw Exception("Failed to fork daemon: "+strError(errno)); else if (pid > 0) { int ret = retval->wait(timeout); // parent, wait for child. if (ret != 0) { string err; if (ret > 0) err = strError(ret); else if (ret == -1) err= strError(errno); else err= "unknown error"; throw Exception("Deamon startup failed: "+err); } } else if (pid == 0) { // child. // TODO aconway 2007-04-26: Should log failures. if (daemon_pid_file_create()) failed(); } return pid; } void Daemon::notify(int i) { assert(retval); if (retval->send(i)) throw Exception("Failed to notify parent: "+strError(errno)); } void Daemon::ready() { notify(0); } // NB: Not -1, confused with failure of fork() on the parent side. void Daemon::failed() { notify(errno? errno:-2); } void Daemon::quit() { if (daemon_pid_file_kill_wait(SIGINT, timeout)) throw Exception("Failed to stop daemon: " + strError(errno)); } void Daemon::kill() { if (daemon_pid_file_kill_wait(SIGKILL, timeout) < 0) throw Exception("Failed to stop daemon: " + strError(errno)); } pid_t Daemon::check() { return daemon_pid_file_is_running(); } Daemon::Retval::Retval() : completed(false) { daemon_retval_init(); } Daemon::Retval::~Retval() { if (!completed) daemon_retval_done(); } int Daemon::Retval::send(int s) { return daemon_retval_send(s); } int Daemon::Retval::wait(int timeout) { return daemon_retval_wait(timeout); } }} // namespace qpid::broker