1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #ifndef CEPH_COMMON_PREFORKER_H
4 #define CEPH_COMMON_PREFORKER_H
6 #include <sys/socket.h>
11 #include "include/assert.h"
12 #include "common/safe_io.h"
13 #include "common/errno.h"
16 * pre-fork fork/daemonize helper class
18 * Hide the details of letting a process fork early, do a bunch of
19 * initialization work that may spam stdout or exit with an error, and
20 * then daemonize. The exit() method will either exit directly (if we
21 * haven't forked) or pass a message to the parent with the error if
27 int fd[2]; // parent's, child's
35 int prefork(std::string &err) {
37 int r = ::socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
38 std::ostringstream oss;
40 oss << "[" << getpid() << "]: unable to create socketpair: " << cpp_strerror(errno);
50 oss << "[" << getpid() << "]: unable to fork: " << cpp_strerror(errno);
62 int get_signal_fd() const {
63 return forked ? fd[1] : 0;
74 int parent_wait(std::string &err_msg) {
78 std::ostringstream oss;
79 int err = safe_read_exact(fd[0], &r, sizeof(r));
80 if (err == 0 && r == -1) {
87 oss << "[" << getpid() << "]: " << cpp_strerror(err);
89 // wait for child to exit
91 err = waitpid(childpid, &status, 0);
93 oss << "[" << getpid() << "]" << " waitpid error: " << cpp_strerror(err);
94 } else if (WIFSIGNALED(status)) {
95 oss << "[" << getpid() << "]" << " exited with a signal";
96 } else if (!WIFEXITED(status)) {
97 oss << "[" << getpid() << "]" << " did not exit normally";
99 err = WEXITSTATUS(status);
101 oss << "[" << getpid() << "]" << " returned exit_status " << cpp_strerror(err);
108 int signal_exit(int r) {
110 // tell parent. this shouldn't fail, but if it does, pass the
111 // error back to the parent.
112 int ret = safe_write(fd[1], &r, sizeof(r));
127 int r2 = ::write(fd[1], &r, sizeof(r));
128 r += r2; // make the compiler shut up about the unused return code from ::write(2).