summaryrefslogtreecommitdiff
path: root/cpp/lib/broker/Daemon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/lib/broker/Daemon.cpp')
-rw-r--r--cpp/lib/broker/Daemon.cpp144
1 files changed, 144 insertions, 0 deletions
diff --git a/cpp/lib/broker/Daemon.cpp b/cpp/lib/broker/Daemon.cpp
new file mode 100644
index 0000000000..d54882a274
--- /dev/null
+++ b/cpp/lib/broker/Daemon.cpp
@@ -0,0 +1,144 @@
+/*
+ *
+ * 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 <libdaemon/daemon.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+
+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<char*>(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