Electroneum
Loading...
Searching...
No Matches
posix_fork.cpp
Go to the documentation of this file.
1// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6
8#include "misc_log_ex.h"
9
10#include <cstdlib>
11#include <fcntl.h>
12#include <unistd.h>
13#include <stdexcept>
14#include <string>
15
16#ifndef TMPDIR
17#define TMPDIR "/tmp"
18#endif
19
20namespace posix {
21
22namespace {
23 void quit(const std::string & message)
24 {
26 throw std::runtime_error(message);
27 }
28}
29
30void fork(const std::string & pidfile)
31{
32 // If a PID file is specified, we open the file here, because
33 // we can't report errors after the fork operation.
34 // When we fork, we close thise file in each of the parent
35 // processes.
36 // Only in the final child process do we write the PID to the
37 // file (and close it).
38 std::ofstream pidofs;
39 if (! pidfile.empty ())
40 {
41 int oldpid;
42 std::ifstream pidrifs;
43 pidrifs.open(pidfile, std::fstream::in);
44 if (! pidrifs.fail())
45 {
46 // Read the PID and send signal 0 to see if the process exists.
47 if (pidrifs >> oldpid && oldpid > 1 && kill(oldpid, 0) == 0)
48 {
49 quit("PID file " + pidfile + " already exists and the PID therein is valid");
50 }
51 pidrifs.close();
52 }
53
54 pidofs.open(pidfile, std::fstream::out | std::fstream::trunc);
55 if (pidofs.fail())
56 {
57 quit("Failed to open specified PID file for writing");
58 }
59 }
60 // Fork the process and have the parent exit. If the process was started
61 // from a shell, this returns control to the user. Forking a new process is
62 // also a prerequisite for the subsequent call to setsid().
63 if (pid_t pid = ::fork())
64 {
65 if (pid > 0)
66 {
67 // We're in the parent process and need to exit.
68 pidofs.close();
69 // When the exit() function is used, the program terminates without
70 // invoking local variables' destructors. Only global variables are
71 // destroyed.
72 exit(0);
73 }
74 else
75 {
76 quit("First fork failed");
77 }
78 }
79
80 // Make the process a new session leader. This detaches it from the
81 // terminal.
82 setsid();
83
84 // A second fork ensures the process cannot acquire a controlling terminal.
85 if (pid_t pid = ::fork())
86 {
87 if (pid > 0)
88 {
89 pidofs.close();
90 exit(0);
91 }
92 else
93 {
94 quit("Second fork failed");
95 }
96 }
97
98 if (! pidofs.fail())
99 {
100 int pid = ::getpid();
101 pidofs << pid << std::endl;
102 pidofs.close();
103 }
104
105 // Close the standard streams. This decouples the daemon from the terminal
106 // that started it.
107 close(0);
108 close(1);
109 close(2);
110
111 // We don't want the daemon to have any standard input.
112 if (open("/dev/null", O_RDONLY) < 0)
113 {
114 quit("Unable to open /dev/null");
115 }
116
117#ifdef DEBUG_TMPDIR_LOG
118 // Send standard output to a log file.
119 const char *tmpdir = getenv("TMPDIR");
120 if (!tmpdir)
121 tmpdir = TMPDIR;
122 std::string output = tmpdir;
123 output += "/electroneum.daemon.stdout.stderr";
124 const int flags = O_WRONLY | O_CREAT | O_APPEND;
125 const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
126 if (open(output.c_str(), flags, mode) < 0)
127 {
128 quit("Unable to open output file: " + output);
129 }
130
131 // Also send standard error to the same log file.
132 if (dup(1) < 0)
133 {
134 quit("Unable to dup output descriptor");
135 }
136#endif
137}
138
139} // namespace posix
std::string message("Message requiring signing")
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
void fork(const std::string &pidfile)
#define TMPDIR