passenger 4.0.2 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (79) hide show
  1. data.tar.gz.asc +7 -7
  2. data/NEWS +27 -0
  3. data/bin/passenger-config +6 -3
  4. data/bin/passenger-install-apache2-module +2 -2
  5. data/bin/passenger-install-nginx-module +16 -2
  6. data/build/agents.rb +4 -0
  7. data/build/apache2.rb +1 -1
  8. data/build/cplusplus_support.rb +1 -1
  9. data/build/cxx_tests.rb +3 -0
  10. data/build/packaging.rb +51 -8
  11. data/build/ruby_extension.rb +1 -1
  12. data/doc/Packaging.txt.md +20 -7
  13. data/doc/Users guide Apache.html +1 -1
  14. data/doc/Users guide Apache.txt +1 -1
  15. data/doc/Users guide Nginx.html +5 -4
  16. data/doc/Users guide Nginx.txt +1 -1
  17. data/doc/users_guide_snippets/installation.txt +5 -3
  18. data/ext/apache2/Configuration.cpp +12 -0
  19. data/ext/apache2/Configuration.hpp +7 -4
  20. data/ext/apache2/Hooks.cpp +29 -19
  21. data/ext/common/AgentsStarter.cpp +85 -57
  22. data/ext/common/AgentsStarter.h +570 -42
  23. data/ext/common/ApplicationPool2/DirectSpawner.h +5 -2
  24. data/ext/common/ApplicationPool2/Implementation.cpp +7 -1
  25. data/ext/common/ApplicationPool2/Pool.h +6 -3
  26. data/ext/common/ApplicationPool2/Process.h +12 -3
  27. data/ext/common/ApplicationPool2/SmartSpawner.h +2 -1
  28. data/ext/common/Constants.h +4 -1
  29. data/ext/common/EventedBufferedInput.h +139 -16
  30. data/ext/common/MultiLibeio.cpp +4 -2
  31. data/ext/common/SafeLibev.h +15 -62
  32. data/ext/common/ServerInstanceDir.h +10 -26
  33. data/ext/common/Utils.cpp +1 -3
  34. data/ext/common/Utils.h +1 -1
  35. data/ext/common/Utils/StrIntUtils.cpp +9 -0
  36. data/ext/common/Utils/StrIntUtils.h +5 -0
  37. data/ext/common/Utils/VariantMap.h +63 -14
  38. data/ext/common/agents/Base.cpp +50 -15
  39. data/ext/common/agents/HelperAgent/AgentOptions.h +20 -12
  40. data/ext/common/agents/HelperAgent/FileBackedPipe.h +1 -1
  41. data/ext/common/agents/HelperAgent/Main.cpp +5 -4
  42. data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
  43. data/ext/common/agents/LoggingAgent/Main.cpp +0 -1
  44. data/ext/common/agents/LoggingAgent/RemoteSender.h +2 -2
  45. data/ext/common/agents/SpawnPreparer.cpp +23 -5
  46. data/ext/common/agents/Watchdog/AgentWatcher.cpp +508 -0
  47. data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +93 -0
  48. data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +68 -0
  49. data/ext/common/agents/Watchdog/Main.cpp +180 -802
  50. data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +111 -0
  51. data/ext/nginx/Configuration.c +107 -92
  52. data/ext/nginx/Configuration.h +1 -0
  53. data/ext/nginx/ContentHandler.c +6 -6
  54. data/ext/nginx/ContentHandler.h +1 -1
  55. data/ext/nginx/config +8 -2
  56. data/ext/nginx/ngx_http_passenger_module.c +54 -60
  57. data/ext/nginx/ngx_http_passenger_module.h +6 -6
  58. data/lib/phusion_passenger.rb +17 -10
  59. data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
  60. data/lib/phusion_passenger/common_library.rb +0 -1
  61. data/lib/phusion_passenger/platform_info.rb +10 -1
  62. data/lib/phusion_passenger/platform_info/depcheck.rb +4 -4
  63. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +2 -2
  64. data/lib/phusion_passenger/platform_info/ruby.rb +7 -0
  65. data/lib/phusion_passenger/request_handler.rb +119 -42
  66. data/lib/phusion_passenger/request_handler/thread_handler.rb +25 -22
  67. data/lib/phusion_passenger/standalone/command.rb +2 -0
  68. data/lib/phusion_passenger/standalone/runtime_installer.rb +4 -3
  69. data/lib/phusion_passenger/standalone/start_command.rb +49 -37
  70. data/resources/templates/nginx/pcre_checksum_could_not_be_verified.txt.erb +11 -0
  71. data/test/cxx/CxxTestMain.cpp +2 -0
  72. data/test/cxx/EventedBufferedInputTest.cpp +758 -0
  73. data/test/cxx/ServerInstanceDirTest.cpp +16 -31
  74. data/test/cxx/TestSupport.cpp +2 -1
  75. data/test/cxx/VariantMapTest.cpp +23 -11
  76. metadata +8 -4
  77. metadata.gz.asc +7 -7
  78. data/ext/common/AgentsStarter.hpp +0 -655
  79. data/lib/phusion_passenger/utils/robust_interruption.rb +0 -173
@@ -0,0 +1,93 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2010-2013 Phusion
4
+ *
5
+ * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ */
25
+
26
+ class HelperAgentWatcher: public AgentWatcher {
27
+ protected:
28
+ string helperAgentFilename;
29
+ VariantMap params, report;
30
+ string requestSocketFilename;
31
+ string messageSocketFilename;
32
+
33
+ virtual const char *name() const {
34
+ return "Phusion Passenger helper agent";
35
+ }
36
+
37
+ virtual string getExeFilename() const {
38
+ return helperAgentFilename;
39
+ }
40
+
41
+ virtual void execProgram() const {
42
+ if (hasEnvOption("PASSENGER_RUN_HELPER_AGENT_IN_VALGRIND", false)) {
43
+ execlp("valgrind", "valgrind", "--dsymutil=yes",
44
+ helperAgentFilename.c_str(), (char *) 0);
45
+ } else {
46
+ execl(helperAgentFilename.c_str(), "PassengerHelperAgent", (char *) 0);
47
+ }
48
+ }
49
+
50
+ virtual void sendStartupArguments(pid_t pid, FileDescriptor &fd) {
51
+ VariantMap options = agentsOptions;
52
+ params.addTo(options);
53
+ options.writeToFd(fd);
54
+ }
55
+
56
+ virtual bool processStartupInfo(pid_t pid, FileDescriptor &fd, const vector<string> &args) {
57
+ if (args[0] == "initialized") {
58
+ requestSocketFilename = args[1];
59
+ messageSocketFilename = args[2];
60
+ return true;
61
+ } else {
62
+ return false;
63
+ }
64
+ }
65
+
66
+ public:
67
+ HelperAgentWatcher(const ResourceLocator &resourceLocator) {
68
+ helperAgentFilename = resourceLocator.getAgentsDir() + "/PassengerHelperAgent";
69
+
70
+ report
71
+ .set("request_socket_filename",
72
+ agentsOptions.get("request_socket_filename", false,
73
+ generation->getPath() + "/request"))
74
+ .set("request_socket_password",
75
+ agentsOptions.get("request_socket_password", false,
76
+ randomGenerator->generateAsciiString(REQUEST_SOCKET_PASSWORD_SIZE)))
77
+ .set("helper_agent_admin_socket_address",
78
+ agentsOptions.get("helper_agent_admin_socket_address", false,
79
+ "unix:" + generation->getPath() + "/helper_admin"))
80
+ .set("helper_agent_exit_password",
81
+ agentsOptions.get("helper_agent_exit_password", false,
82
+ randomGenerator->generateAsciiString(MESSAGE_SERVER_MAX_PASSWORD_SIZE)));
83
+
84
+ params = report;
85
+ params
86
+ .set("logging_agent_address", loggingAgentAddress)
87
+ .set("logging_agent_password", loggingAgentPassword);
88
+ }
89
+
90
+ virtual void reportAgentsInformation(VariantMap &report) {
91
+ this->report.addTo(report);
92
+ }
93
+ };
@@ -0,0 +1,68 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2010-2013 Phusion
4
+ *
5
+ * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ */
25
+
26
+ class LoggingAgentWatcher: public AgentWatcher {
27
+ protected:
28
+ string agentFilename;
29
+ string socketAddress;
30
+
31
+ virtual const char *name() const {
32
+ return "Phusion Passenger logging agent";
33
+ }
34
+
35
+ virtual string getExeFilename() const {
36
+ return agentFilename;
37
+ }
38
+
39
+ virtual void execProgram() const {
40
+ execl(agentFilename.c_str(), "PassengerLoggingAgent", (char *) 0);
41
+ }
42
+
43
+ virtual void sendStartupArguments(pid_t pid, FileDescriptor &fd) {
44
+ VariantMap options = agentsOptions;
45
+ options.set("logging_agent_address", loggingAgentAddress);
46
+ options.set("logging_agent_password", loggingAgentPassword);
47
+ options.writeToFd(fd);
48
+ }
49
+
50
+ virtual bool processStartupInfo(pid_t pid, FileDescriptor &fd, const vector<string> &args) {
51
+ if (args[0] == "initialized") {
52
+ return true;
53
+ } else {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ public:
59
+ LoggingAgentWatcher(const ResourceLocator &resourceLocator) {
60
+ agentFilename = resourceLocator.getAgentsDir() + "/PassengerLoggingAgent";
61
+ }
62
+
63
+ virtual void reportAgentsInformation(VariantMap &report) {
64
+ report
65
+ .set("logging_socket_address", loggingAgentAddress)
66
+ .set("logging_socket_password", loggingAgentPassword);
67
+ }
68
+ };
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2012 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -27,6 +27,7 @@
27
27
  #include <boost/function.hpp>
28
28
  #include <boost/bind.hpp>
29
29
  #include <boost/make_shared.hpp>
30
+ #include <boost/foreach.hpp>
30
31
  #include <boost/enable_shared_from_this.hpp>
31
32
  #include <string>
32
33
 
@@ -63,713 +64,44 @@ using namespace oxt;
63
64
  using namespace Passenger;
64
65
 
65
66
 
67
+ enum OomFileType {
68
+ OOM_ADJ,
69
+ OOM_SCORE_ADJ
70
+ };
71
+
72
+ #define REQUEST_SOCKET_PASSWORD_SIZE 64
73
+
74
+ class ServerInstanceDirToucher;
75
+ static bool hasEnvOption(const char *name, bool defaultValue = false);
76
+ static void setOomScore(const StaticString &score);
77
+
78
+
66
79
  /** The options that were passed to AgentsStarter. */
67
- static VariantMap agentsOptions;
68
- static pid_t webServerPid;
80
+ static VariantMap agentsOptions;
69
81
  static string tempDir;
70
82
  static bool userSwitching;
71
83
  static string defaultUser;
72
84
  static string defaultGroup;
73
85
  static uid_t webServerWorkerUid;
74
86
  static gid_t webServerWorkerGid;
75
- static string passengerRoot;
76
87
  static string serializedPrestartURLs;
77
88
 
89
+ /***** Working objects *****/
78
90
  static string oldOomScore;
91
+ static RandomGenerator *randomGenerator;
92
+ static EventFd *errorEvent;
93
+ static ResourceLocator *resourceLocator;
79
94
  static ServerInstanceDirPtr serverInstanceDir;
80
95
  static ServerInstanceDir::GenerationPtr generation;
96
+ static ServerInstanceDirToucher *serverInstanceDirToucher;
81
97
  static string loggingAgentAddress;
82
98
  static string loggingAgentPassword;
83
- static RandomGenerator *randomGenerator;
84
- static EventFd *errorEvent;
85
-
86
- #define REQUEST_SOCKET_PASSWORD_SIZE 64
87
-
88
- static bool hasEnvOption(const char *name, bool defaultValue = false);
89
- static void setOomScore(const StaticString &score);
90
-
91
-
92
- /**
93
- * Abstract base class for watching agent processes.
94
- */
95
- class AgentWatcher: public enable_shared_from_this<AgentWatcher> {
96
- private:
97
- /** The watcher thread. */
98
- oxt::thread *thr;
99
-
100
- void threadMain(shared_ptr<AgentWatcher> self) {
101
- try {
102
- pid_t pid, ret;
103
- int status, e;
104
-
105
- while (!this_thread::interruption_requested()) {
106
- {
107
- lock_guard<boost::mutex> l(lock);
108
- pid = this->pid;
109
- }
110
-
111
- // Process can be started before the watcher thread is launched.
112
- if (pid == 0) {
113
- pid = start();
114
- }
115
- ret = syscalls::waitpid(pid, &status, 0);
116
- if (ret == -1 && errno == ECHILD) {
117
- /* If the agent is attached to gdb then waitpid()
118
- * here can return -1 with errno == ECHILD.
119
- * Fallback to kill() polling for checking
120
- * whether the agent is alive.
121
- */
122
- ret = pid;
123
- status = 0;
124
- P_WARN("waitpid() on " << name() << " (pid=" << pid <<
125
- ") returned -1 with " <<
126
- "errno = ECHILD, falling back to kill polling");
127
- waitpidUsingKillPolling(pid);
128
- e = 0;
129
- } else {
130
- e = errno;
131
- }
132
-
133
- {
134
- lock_guard<boost::mutex> l(lock);
135
- this->pid = 0;
136
- }
137
-
138
- this_thread::disable_interruption di;
139
- this_thread::disable_syscall_interruption dsi;
140
- if (ret == -1) {
141
- P_WARN(name() << " (pid=" << pid << ") crashed or killed for "
142
- "an unknown reason (errno = " <<
143
- strerror(e) << "), restarting it...");
144
- } else if (WIFEXITED(status)) {
145
- if (WEXITSTATUS(status) == 0) {
146
- /* When the web server is gracefully exiting, it will
147
- * tell one or more agents to gracefully exit with exit
148
- * status 0. If we see this then it means the watchdog
149
- * is gracefully shutting down too and we should stop
150
- * watching.
151
- */
152
- return;
153
- } else {
154
- P_WARN(name() << " (pid=" << pid <<
155
- ") crashed with exit status " <<
156
- WEXITSTATUS(status) << ", restarting it...");
157
- }
158
- } else {
159
- P_WARN(name() << " (pid=" << pid <<
160
- ") crashed with signal " <<
161
- getSignalName(WTERMSIG(status)) <<
162
- ", restarting it...");
163
- }
164
-
165
- const char *sleepTime;
166
- if ((sleepTime = getenv("PASSENGER_AGENT_RESTART_SLEEP")) != NULL) {
167
- sleep(atoi(sleepTime));
168
- }
169
- }
170
- } catch (const boost::thread_interrupted &) {
171
- } catch (const tracable_exception &e) {
172
- lock_guard<boost::mutex> l(lock);
173
- threadExceptionMessage = e.what();
174
- threadExceptionBacktrace = e.backtrace();
175
- errorEvent->notify();
176
- } catch (const std::exception &e) {
177
- lock_guard<boost::mutex> l(lock);
178
- threadExceptionMessage = e.what();
179
- errorEvent->notify();
180
- } catch (...) {
181
- lock_guard<boost::mutex> l(lock);
182
- threadExceptionMessage = "Unknown error";
183
- errorEvent->notify();
184
- }
185
- }
186
-
187
- protected:
188
- /** PID of the process we're watching. 0 if no process is started at this time. */
189
- pid_t pid;
190
-
191
- /** If the watcher thread threw an uncaught exception then its information will
192
- * be stored here so that the main thread can check whether a watcher encountered
193
- * an error. These are empty strings if everything is OK.
194
- */
195
- string threadExceptionMessage;
196
- string threadExceptionBacktrace;
197
-
198
- /** The agent process's feedback fd. */
199
- FileDescriptor feedbackFd;
200
-
201
- /**
202
- * Lock for protecting the exchange of data between the main thread and
203
- * the watcher thread.
204
- */
205
- mutable boost::mutex lock;
206
-
207
- /**
208
- * Returns the filename of the agent process's executable. This method may be
209
- * called in a forked child process and may therefore not allocate memory.
210
- */
211
- virtual string getExeFilename() const = 0;
212
-
213
- /**
214
- * This method is to exec() the agent with the right arguments.
215
- * It is called from within a forked child process, so don't do any dynamic
216
- * memory allocations in here. It must also not throw any exceptions.
217
- * It must also preserve the value of errno after exec() is called.
218
- */
219
- virtual void execProgram() const {
220
- execl(getExeFilename().c_str(),
221
- getExeFilename().c_str(),
222
- "3", // feedback fd
223
- (char *) 0);
224
- }
225
-
226
- /**
227
- * This method is to send startup arguments to the agent process through
228
- * the given file descriptor, which is the agent process's feedback fd.
229
- * May throw arbitrary exceptions.
230
- */
231
- virtual void sendStartupArguments(pid_t pid, FileDescriptor &fd) = 0;
232
-
233
- /**
234
- * This method is to process the startup info that the agent process has
235
- * sent back. May throw arbitrary exceptions.
236
- */
237
- virtual bool processStartupInfo(pid_t pid, FileDescriptor &fd, const vector<string> &args) = 0;
238
-
239
- /**
240
- * Kill a process with SIGKILL, and attempt to kill its children too.
241
- * Then wait until it has quit.
242
- */
243
- static void killAndWait(pid_t pid) {
244
- this_thread::disable_interruption di;
245
- this_thread::disable_syscall_interruption dsi;
246
- // If the process is a process group leader then killing the
247
- // group will likely kill all its child processes too.
248
- if (syscalls::killpg(pid, SIGKILL) == -1) {
249
- syscalls::kill(pid, SIGKILL);
250
- }
251
- syscalls::waitpid(pid, NULL, 0);
252
- }
253
-
254
- /**
255
- * Behaves like <tt>waitpid(pid, status, WNOHANG)</tt>, but waits at most
256
- * <em>timeout</em> miliseconds for the process to exit.
257
- */
258
- static int timedWaitPid(pid_t pid, int *status, unsigned long long timeout) {
259
- Timer timer;
260
- int ret;
261
-
262
- do {
263
- ret = syscalls::waitpid(pid, status, WNOHANG);
264
- if (ret > 0 || ret == -1) {
265
- return ret;
266
- } else {
267
- syscalls::usleep(10000);
268
- }
269
- } while (timer.elapsed() < timeout);
270
- return 0; // timed out
271
- }
272
-
273
- static void waitpidUsingKillPolling(pid_t pid) {
274
- bool done = false;
275
-
276
- while (!done) {
277
- int ret = syscalls::kill(pid, 0);
278
- done = ret == -1;
279
- if (!done) {
280
- syscalls::usleep(20000);
281
- }
282
- }
283
- }
284
-
285
- public:
286
- AgentWatcher() {
287
- thr = NULL;
288
- pid = 0;
289
- }
290
-
291
- virtual ~AgentWatcher() {
292
- delete thr;
293
- }
294
-
295
- /**
296
- * Send the started agent process's startup information over the given
297
- * file descriptor, to the starter process. May throw arbitrary exceptions.
298
- *
299
- * @pre start() has been called and succeeded.
300
- */
301
- virtual void sendStartupInfo(int fd) = 0;
302
-
303
- /** Returns the name of the agent that this class is watching. */
304
- virtual const char *name() const = 0;
305
-
306
- /**
307
- * Starts the agent process. May throw arbitrary exceptions.
308
- */
309
- virtual pid_t start() {
310
- this_thread::disable_interruption di;
311
- this_thread::disable_syscall_interruption dsi;
312
- string exeFilename = getExeFilename();
313
- SocketPair fds;
314
- int e, ret;
315
- pid_t pid;
316
-
317
- /* Create feedback fd for this agent process. We'll send some startup
318
- * arguments to this agent process through this fd, and we'll receive
319
- * startup information through it as well.
320
- */
321
- fds = createUnixSocketPair();
322
-
323
- pid = syscalls::fork();
324
- if (pid == 0) {
325
- // Child
326
-
327
- /* Make sure file descriptor FEEDBACK_FD refers to the newly created
328
- * feedback fd (fds[1]) and close all other file descriptors.
329
- * In this child process we don't care about the original FEEDBACK_FD
330
- * (which is the Watchdog's communication channel to the agents starter.)
331
- *
332
- * fds[1] is guaranteed to be != FEEDBACK_FD because the watchdog
333
- * is started with FEEDBACK_FD already assigned.
334
- */
335
- syscalls::close(fds[0]);
336
-
337
- if (syscalls::dup2(fds[1], FEEDBACK_FD) == -1) {
338
- /* Something went wrong, report error through feedback fd. */
339
- e = errno;
340
- try {
341
- writeArrayMessage(fds[1],
342
- "system error before exec",
343
- "dup2() failed",
344
- toString(e).c_str(),
345
- NULL);
346
- _exit(1);
347
- } catch (...) {
348
- fprintf(stderr, "Passenger Watchdog: dup2() failed: %s (%d)\n",
349
- strerror(e), e);
350
- fflush(stderr);
351
- _exit(1);
352
- }
353
- }
354
-
355
- closeAllFileDescriptors(FEEDBACK_FD);
356
-
357
- /* Become the process group leader so that the watchdog can kill the
358
- * agent as well as all its descendant processes. */
359
- setpgid(getpid(), getpid());
360
-
361
- setOomScore(oldOomScore);
362
-
363
- try {
364
- execProgram();
365
- } catch (...) {
366
- fprintf(stderr, "PassengerWatchdog: execProgram() threw an exception\n");
367
- fflush(stderr);
368
- _exit(1);
369
- }
370
- e = errno;
371
- try {
372
- writeArrayMessage(FEEDBACK_FD,
373
- "exec error",
374
- toString(e).c_str(),
375
- NULL);
376
- } catch (...) {
377
- fprintf(stderr, "Passenger Watchdog: could not execute %s: %s (%d)\n",
378
- exeFilename.c_str(), strerror(e), e);
379
- fflush(stderr);
380
- }
381
- _exit(1);
382
- } else if (pid == -1) {
383
- // Error
384
- e = errno;
385
- throw SystemException("Cannot fork a new process", e);
386
- } else {
387
- // Parent
388
- FileDescriptor feedbackFd = fds[0];
389
- vector<string> args;
390
-
391
- fds[1].close();
392
- this_thread::restore_interruption ri(di);
393
- this_thread::restore_syscall_interruption rsi(dsi);
394
- ScopeGuard failGuard(boost::bind(killAndWait, pid));
395
-
396
- /* Send startup arguments. Ignore EPIPE and ECONNRESET here
397
- * because the child process might have sent an feedback message
398
- * without reading startup arguments.
399
- */
400
- try {
401
- sendStartupArguments(pid, feedbackFd);
402
- } catch (const SystemException &ex) {
403
- if (ex.code() != EPIPE && ex.code() != ECONNRESET) {
404
- throw SystemException(string("Unable to start the ") + name() +
405
- ": an error occurred while sending startup arguments",
406
- ex.code());
407
- }
408
- }
409
-
410
- // Now read its feedback.
411
- try {
412
- ret = readArrayMessage(feedbackFd, args);
413
- } catch (const SystemException &e) {
414
- if (e.code() == ECONNRESET) {
415
- ret = false;
416
- } else {
417
- throw SystemException(string("Unable to start the ") + name() +
418
- ": unable to read its startup information",
419
- e.code());
420
- }
421
- }
422
- if (!ret) {
423
- this_thread::disable_interruption di2;
424
- this_thread::disable_syscall_interruption dsi2;
425
- int status;
426
-
427
- /* The feedback fd was prematurely closed for an unknown reason.
428
- * Did the agent process crash?
429
- *
430
- * We use timedWaitPid() here because if the process crashed
431
- * because of an uncaught exception, the file descriptor
432
- * might be closed before the process has printed an error
433
- * message, so we give it some time to print the error
434
- * before we kill it.
435
- */
436
- ret = timedWaitPid(pid, &status, 5000);
437
- if (ret == 0) {
438
- /* Doesn't look like it; it seems it's still running.
439
- * We can't do anything without proper feedback so kill
440
- * the agent process and throw an exception.
441
- */
442
- failGuard.runNow();
443
- throw RuntimeException(string("Unable to start the ") + name() +
444
- ": it froze and reported an unknown error during its startup");
445
- } else if (ret != -1 && WIFSIGNALED(status)) {
446
- /* Looks like a crash which caused a signal. */
447
- throw RuntimeException(string("Unable to start the ") + name() +
448
- ": it seems to have been killed with signal " +
449
- getSignalName(WTERMSIG(status)) + " during startup");
450
- } else if (ret == -1) {
451
- /* Looks like it exited after detecting an error. */
452
- throw RuntimeException(string("Unable to start the ") + name() +
453
- ": it seems to have crashed during startup for an unknown reason");
454
- } else {
455
- /* Looks like it exited after detecting an error, but has an exit code. */
456
- throw RuntimeException(string("Unable to start the ") + name() +
457
- ": it seems to have crashed during startup for an unknown reason, "
458
- "with exit code " + toString(WEXITSTATUS(status)));
459
- }
460
- }
461
-
462
- if (args[0] == "system error before exec") {
463
- throw SystemException(string("Unable to start the ") + name() +
464
- ": " + args[1], atoi(args[2]));
465
- } else if (args[0] == "exec error") {
466
- e = atoi(args[1]);
467
- if (e == ENOENT) {
468
- throw RuntimeException(string("Unable to start the ") + name() +
469
- " because its executable (" + getExeFilename() + ") "
470
- "doesn't exist. This probably means that your "
471
- "Phusion Passenger installation is broken or "
472
- "incomplete. Please reinstall Phusion Passenger");
473
- } else {
474
- throw SystemException(string("Unable to start the ") + name() +
475
- " because exec(\"" + getExeFilename() + "\") failed",
476
- atoi(args[1]));
477
- }
478
- } else if (!processStartupInfo(pid, feedbackFd, args)) {
479
- throw RuntimeException(string("The ") + name() +
480
- " sent an unknown startup info message '" +
481
- args[0] + "'");
482
- }
483
-
484
- lock_guard<boost::mutex> l(lock);
485
- this->feedbackFd = feedbackFd;
486
- this->pid = pid;
487
- failGuard.clear();
488
- return pid;
489
- }
490
- }
491
-
492
- /**
493
- * Start watching the agent process.
494
- *
495
- * @pre start() has been called and succeeded.
496
- * @pre This watcher isn't already watching.
497
- * @throws RuntimeException If a precondition failed.
498
- * @throws thread_interrupted
499
- * @throws thread_resource_error
500
- */
501
- virtual void startWatching() {
502
- lock_guard<boost::mutex> l(lock);
503
- if (pid == 0) {
504
- throw RuntimeException("start() hasn't been called yet");
505
- }
506
- if (thr != NULL) {
507
- throw RuntimeException("Already started watching.");
508
- }
509
-
510
- thr = new oxt::thread(boost::bind(&AgentWatcher::threadMain, this, shared_from_this()),
511
- name(), 256 * 1024);
512
- }
513
-
514
- static void stopWatching(vector< shared_ptr<AgentWatcher> > &watchers) {
515
- vector< shared_ptr<AgentWatcher> >::const_iterator it;
516
- oxt::thread *threads[watchers.size()];
517
- unsigned int i = 0;
518
-
519
- for (it = watchers.begin(); it != watchers.end(); it++, i++) {
520
- threads[i] = (*it)->thr;
521
- }
522
-
523
- oxt::thread::interrupt_and_join_multiple(threads, watchers.size());
524
- for (it = watchers.begin(); it != watchers.end(); it++, i++) {
525
- delete (*it)->thr;
526
- (*it)->thr = NULL;
527
- }
528
- }
529
-
530
- /**
531
- * Force the agent process to shut down. Returns true if it was shut down,
532
- * or false if it wasn't started.
533
- */
534
- virtual bool forceShutdown() {
535
- lock_guard<boost::mutex> l(lock);
536
- if (pid == 0) {
537
- return false;
538
- } else {
539
- killAndWait(pid);
540
- this->pid = 0;
541
- return true;
542
- }
543
- }
544
-
545
- /**
546
- * If the watcher thread has encountered an error, then the error message
547
- * will be stored here. If the error message is empty then it means
548
- * everything is still OK.
549
- */
550
- string getErrorMessage() const {
551
- lock_guard<boost::mutex> l(lock);
552
- return threadExceptionMessage;
553
- }
554
-
555
- /**
556
- * The error backtrace, if applicable.
557
- */
558
- string getErrorBacktrace() const {
559
- lock_guard<boost::mutex> l(lock);
560
- return threadExceptionBacktrace;
561
- }
562
-
563
- /**
564
- * Returns the agent process feedback fd, or -1 if the agent process
565
- * hasn't been started yet. Can be used to check whether this agent process
566
- * has exited without using waitpid().
567
- */
568
- const FileDescriptor getFeedbackFd() const {
569
- lock_guard<boost::mutex> l(lock);
570
- return feedbackFd;
571
- }
572
- };
573
-
574
- typedef shared_ptr<AgentWatcher> AgentWatcherPtr;
575
-
576
-
577
- class HelperAgentWatcher: public AgentWatcher {
578
- protected:
579
- string requestSocketFilename;
580
- string messageSocketFilename;
581
- string helperAgentFilename;
582
- string requestSocketPassword;
583
- string messageSocketPassword;
584
-
585
- virtual const char *name() const {
586
- return "Phusion Passenger helper agent";
587
- }
588
-
589
- virtual string getExeFilename() const {
590
- return helperAgentFilename;
591
- }
592
-
593
- virtual void execProgram() const {
594
- if (hasEnvOption("PASSENGER_RUN_HELPER_AGENT_IN_VALGRIND", false)) {
595
- execlp("valgrind", "valgrind", "--dsymutil=yes",
596
- helperAgentFilename.c_str(), (char *) 0);
597
- } else {
598
- execl(helperAgentFilename.c_str(), "PassengerHelperAgent", (char *) 0);
599
- }
600
- }
601
-
602
- virtual void sendStartupArguments(pid_t pid, FileDescriptor &fd) {
603
- VariantMap options = agentsOptions;
604
- options.set("request_socket_password", Base64::encode(requestSocketPassword)).
605
- set("message_socket_password", Base64::encode(messageSocketPassword)).
606
- set("logging_agent_address", loggingAgentAddress).
607
- set("logging_agent_password", loggingAgentPassword);
608
- options.writeToFd(fd);
609
- }
610
-
611
- virtual bool processStartupInfo(pid_t pid, FileDescriptor &fd, const vector<string> &args) {
612
- if (args[0] == "initialized") {
613
- requestSocketFilename = args[1];
614
- messageSocketFilename = args[2];
615
- return true;
616
- } else {
617
- return false;
618
- }
619
- }
620
-
621
- public:
622
- HelperAgentWatcher(const ResourceLocator &resourceLocator) {
623
- helperAgentFilename = resourceLocator.getAgentsDir() + "/PassengerHelperAgent";
624
- requestSocketPassword = randomGenerator->generateByteString(REQUEST_SOCKET_PASSWORD_SIZE);
625
- messageSocketPassword = randomGenerator->generateByteString(MESSAGE_SERVER_MAX_PASSWORD_SIZE);
626
- }
627
-
628
- virtual void sendStartupInfo(int fd) {
629
- writeArrayMessage(fd,
630
- "HelperAgent info",
631
- requestSocketFilename.c_str(),
632
- Base64::encode(requestSocketPassword).c_str(),
633
- messageSocketFilename.c_str(),
634
- Base64::encode(messageSocketPassword).c_str(),
635
- NULL);
636
- }
637
- };
638
99
 
639
-
640
- class LoggingAgentWatcher: public AgentWatcher {
641
- protected:
642
- string agentFilename;
643
- string socketAddress;
644
-
645
- virtual const char *name() const {
646
- return "Phusion Passenger logging agent";
647
- }
648
-
649
- virtual string getExeFilename() const {
650
- return agentFilename;
651
- }
652
-
653
- virtual void execProgram() const {
654
- execl(agentFilename.c_str(), "PassengerLoggingAgent", (char *) 0);
655
- }
656
-
657
- virtual void sendStartupArguments(pid_t pid, FileDescriptor &fd) {
658
- VariantMap options = agentsOptions;
659
- options.set("logging_agent_address", loggingAgentAddress);
660
- options.set("logging_agent_password", loggingAgentPassword);
661
- options.writeToFd(fd);
662
- }
663
-
664
- virtual bool processStartupInfo(pid_t pid, FileDescriptor &fd, const vector<string> &args) {
665
- if (args[0] == "initialized") {
666
- return true;
667
- } else {
668
- return false;
669
- }
670
- }
671
-
672
- public:
673
- LoggingAgentWatcher(const ResourceLocator &resourceLocator) {
674
- agentFilename = resourceLocator.getAgentsDir() + "/PassengerLoggingAgent";
675
- }
676
-
677
- virtual void sendStartupInfo(int fd) {
678
- writeArrayMessage(fd,
679
- "LoggingServer info",
680
- loggingAgentAddress.c_str(),
681
- loggingAgentPassword.c_str(),
682
- NULL);
683
- }
684
- };
685
-
686
-
687
- /**
688
- * Touch all files in the server instance dir every 6 hours in order to prevent /tmp
689
- * cleaners from weaking havoc:
690
- * http://code.google.com/p/phusion-passenger/issues/detail?id=365
691
- */
692
- class ServerInstanceDirToucher {
693
- private:
694
- oxt::thread *thr;
695
-
696
- static void
697
- threadMain() {
698
- while (!this_thread::interruption_requested()) {
699
- syscalls::sleep(60 * 60 * 6);
700
-
701
- begin_touch:
702
-
703
- this_thread::disable_interruption di;
704
- this_thread::disable_syscall_interruption dsi;
705
- // Fork a process which touches everything in the server instance dir.
706
- pid_t pid = syscalls::fork();
707
- if (pid == 0) {
708
- // Child
709
- int prio, ret, e;
710
-
711
- closeAllFileDescriptors(2);
712
-
713
- // Make process nicer.
714
- do {
715
- prio = getpriority(PRIO_PROCESS, getpid());
716
- } while (prio == -1 && errno == EINTR);
717
- if (prio != -1) {
718
- prio++;
719
- if (prio > 20) {
720
- prio = 20;
721
- }
722
- do {
723
- ret = setpriority(PRIO_PROCESS, getpid(), prio);
724
- } while (ret == -1 && errno == EINTR);
725
- } else {
726
- perror("getpriority");
727
- }
728
-
729
- do {
730
- ret = chdir(serverInstanceDir->getPath().c_str());
731
- } while (ret == -1 && errno == EINTR);
732
- if (ret == -1) {
733
- e = errno;
734
- fprintf(stderr, "chdir(\"%s\") failed: %s (%d)\n",
735
- serverInstanceDir->getPath().c_str(),
736
- strerror(e), e);
737
- fflush(stderr);
738
- _exit(1);
739
- }
740
-
741
- setOomScore(oldOomScore);
742
-
743
- execlp("/bin/sh", "/bin/sh", "-c", "find . | xargs touch", (char *) 0);
744
- e = errno;
745
- fprintf(stderr, "Cannot execute 'find . | xargs touch': %s (%d)\n",
746
- strerror(e), e);
747
- fflush(stderr);
748
- _exit(1);
749
- } else if (pid == -1) {
750
- // Error
751
- P_WARN("Could not touch the server instance directory because "
752
- "fork() failed. Retrying in 2 minutes...");
753
- this_thread::restore_interruption si(di);
754
- this_thread::restore_syscall_interruption rsi(dsi);
755
- syscalls::sleep(60 * 2);
756
- goto begin_touch;
757
- } else {
758
- syscalls::waitpid(pid, NULL, 0);
759
- }
760
- }
761
- }
762
-
763
- public:
764
- ServerInstanceDirToucher() {
765
- thr = new oxt::thread(threadMain, "Server instance dir toucher", 256 * 1024);
766
- }
767
-
768
- ~ServerInstanceDirToucher() {
769
- thr->interrupt_and_join();
770
- delete thr;
771
- }
772
- };
100
+ #include "AgentWatcher.cpp"
101
+ #include "HelperAgentWatcher.cpp"
102
+ #include "LoggingAgentWatcher.cpp"
103
+ #include "ServerInstanceDirToucher.cpp"
104
+ static vector<AgentWatcherPtr> watchers;
773
105
 
774
106
 
775
107
  static bool
@@ -790,11 +122,6 @@ hasEnvOption(const char *name, bool defaultValue) {
790
122
  }
791
123
  }
792
124
 
793
- enum OomFileType {
794
- OOM_ADJ,
795
- OOM_SCORE_ADJ
796
- };
797
-
798
125
  static FILE *
799
126
  openOomAdjFile(const char *mode, OomFileType &type) {
800
127
  FILE *f = fopen("/proc/self/oom_score_adj", mode);
@@ -833,6 +160,9 @@ setOomScore(const StaticString &score) {
833
160
  }
834
161
  }
835
162
 
163
+ /**
164
+ * Set the current process's OOM score to "never kill".
165
+ */
836
166
  static string
837
167
  setOomScoreNeverKill() {
838
168
  string oldScore;
@@ -929,12 +259,12 @@ waitForStarterProcessOrWatchers(vector<AgentWatcherPtr> &watchers) {
929
259
  }
930
260
 
931
261
  static void
932
- cleanupAgentsInBackground(vector<AgentWatcherPtr> &watchers) {
262
+ cleanupAgentsInBackground(vector<AgentWatcherPtr> &watchers, char *argv[]) {
933
263
  this_thread::disable_interruption di;
934
264
  this_thread::disable_syscall_interruption dsi;
935
265
  pid_t pid;
936
266
  int e;
937
-
267
+
938
268
  pid = fork();
939
269
  if (pid == 0) {
940
270
  // Child
@@ -943,6 +273,11 @@ cleanupAgentsInBackground(vector<AgentWatcherPtr> &watchers) {
943
273
  fd_set fds, fds2;
944
274
  int max, agentProcessesDone;
945
275
  unsigned long long deadline = 30000; // miliseconds
276
+
277
+ #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(sun)
278
+ // Change process title.
279
+ strcpy(argv[0], "PassengerWatchdog (cleaning up...)");
280
+ #endif
946
281
 
947
282
  // Wait until all agent processes have exited. The starter
948
283
  // process is responsible for telling the individual agents
@@ -991,8 +326,8 @@ cleanupAgentsInBackground(vector<AgentWatcherPtr> &watchers) {
991
326
  P_DEBUG("All Phusion Passenger agent processes have exited. Forcing all subprocesses to shut down.");
992
327
  }
993
328
  for (it = watchers.begin(); it != watchers.end(); it++) {
994
- (*it)->forceShutdown();
995
- }
329
+ (*it)->forceShutdown();
330
+ }
996
331
 
997
332
  // Now clean up the server instance directory.
998
333
  delete generation.get();
@@ -1044,8 +379,8 @@ inferDefaultGroup(const string &defaultUser) {
1044
379
  return groupEntry->gr_name;
1045
380
  }
1046
381
 
1047
- int
1048
- main(int argc, char *argv[]) {
382
+ static void
383
+ initializeBareEssentials(int argc, char *argv[]) {
1049
384
  /*
1050
385
  * Some Apache installations (like on OS X) redirect stdout to /dev/null,
1051
386
  * so that only stderr is redirected to the log file. We therefore
@@ -1066,6 +401,11 @@ main(int argc, char *argv[]) {
1066
401
  oldOomScore = setOomScoreNeverKill();
1067
402
 
1068
403
  agentsOptions = initializeAgent(argc, argv, "PassengerWatchdog");
404
+ }
405
+
406
+ static void
407
+ initializeOptions() {
408
+ TRACE_POINT();
1069
409
  agentsOptions
1070
410
  .setDefaultInt ("log_level", DEFAULT_LOG_LEVEL)
1071
411
  .setDefault ("temp_dir", getSystemTempDir())
@@ -1080,111 +420,152 @@ main(int argc, char *argv[]) {
1080
420
  .setDefaultInt ("max_instances_per_app", DEFAULT_MAX_INSTANCES_PER_APP)
1081
421
  .setDefaultInt ("pool_idle_time", DEFAULT_POOL_IDLE_TIME);
1082
422
 
1083
- P_DEBUG("Starting Watchdog...");
1084
-
1085
- try {
1086
- TRACE_POINT();
1087
- // Required options
1088
- passengerRoot = agentsOptions.get("passenger_root");
1089
- webServerPid = agentsOptions.getPid("web_server_pid");
423
+ // Check for required options
424
+ UPDATE_TRACE_POINT();
425
+ agentsOptions.get("passenger_root");
426
+ agentsOptions.getPid("web_server_pid");
1090
427
 
1091
- // Optional options
1092
- UPDATE_TRACE_POINT();
1093
- tempDir = agentsOptions.get("temp_dir");
1094
- userSwitching = agentsOptions.getBool("user_switching");
1095
- defaultUser = agentsOptions.get("default_user");
1096
- if (!agentsOptions.has("default_group")) {
1097
- agentsOptions.set("default_group", inferDefaultGroup(defaultUser));
1098
- }
1099
- defaultGroup = agentsOptions.get("default_group");
1100
- webServerWorkerUid = agentsOptions.getUid("web_server_worker_uid");
1101
- webServerWorkerGid = agentsOptions.getGid("web_server_worker_gid");
428
+ // Fetch optional options
429
+ UPDATE_TRACE_POINT();
430
+ tempDir = agentsOptions.get("temp_dir");
431
+ userSwitching = agentsOptions.getBool("user_switching");
432
+ defaultUser = agentsOptions.get("default_user");
433
+ if (!agentsOptions.has("default_group")) {
434
+ agentsOptions.set("default_group", inferDefaultGroup(defaultUser));
435
+ }
436
+ defaultGroup = agentsOptions.get("default_group");
437
+ webServerWorkerUid = agentsOptions.getUid("web_server_worker_uid");
438
+ webServerWorkerGid = agentsOptions.getGid("web_server_worker_gid");
1102
439
 
1103
- UPDATE_TRACE_POINT();
1104
- randomGenerator = new RandomGenerator();
1105
- errorEvent = new EventFd();
1106
-
1107
- UPDATE_TRACE_POINT();
1108
- serverInstanceDir.reset(new ServerInstanceDir(webServerPid, tempDir));
1109
- generation = serverInstanceDir->newGeneration(userSwitching, defaultUser,
1110
- defaultGroup, webServerWorkerUid, webServerWorkerGid);
440
+ P_INFO("Options: " << agentsOptions.inspect());
441
+ }
442
+
443
+ static void
444
+ initializeWorkingObjects() {
445
+ TRACE_POINT();
446
+ randomGenerator = new RandomGenerator();
447
+ errorEvent = new EventFd();
448
+ resourceLocator = new ResourceLocator(agentsOptions.get("passenger_root"));
449
+
450
+ UPDATE_TRACE_POINT();
451
+ // Must not used make_shared() here because Watchdog.cpp
452
+ // deletes the raw pointer in cleanupAgentsInBackground().
453
+ if (agentsOptions.get("server_instance_dir", false).empty()) {
454
+ /* We embed the super structure version in the server instance directory name
455
+ * because it's possible to upgrade Phusion Passenger without changing the
456
+ * web server's PID. This way each incompatible upgrade will use its own
457
+ * server instance directory.
458
+ */
459
+ string path = tempDir +
460
+ "/passenger." +
461
+ toString(ServerInstanceDir::DIR_STRUCTURE_MAJOR_VERSION) + "." +
462
+ toString(ServerInstanceDir::DIR_STRUCTURE_MINOR_VERSION) + "." +
463
+ toString<unsigned long long>(agentsOptions.getPid("web_server_pid"));
464
+ serverInstanceDir.reset(new ServerInstanceDir(path));
465
+ } else {
466
+ serverInstanceDir.reset(new ServerInstanceDir(agentsOptions.get("server_instance_dir")));
1111
467
  agentsOptions.set("server_instance_dir", serverInstanceDir->getPath());
1112
- agentsOptions.setInt("generation_number", generation->getNumber());
1113
-
1114
- UPDATE_TRACE_POINT();
1115
- ServerInstanceDirToucher serverInstanceDirToucher;
1116
- ResourceLocator resourceLocator(passengerRoot);
1117
- if (agentsOptions.get("analytics_server", false).empty()) {
1118
- // Using local, server instance specific logging agent.
1119
- loggingAgentAddress = "unix:" + generation->getPath() + "/logging.socket";
1120
- loggingAgentPassword = randomGenerator->generateAsciiString(64);
1121
- } else {
1122
- // Using remote logging agent.
1123
- loggingAgentAddress = agentsOptions.get("analytics_server");
1124
- }
1125
-
1126
- UPDATE_TRACE_POINT();
1127
- shared_ptr<HelperAgentWatcher> helperAgentWatcher =
1128
- make_shared<HelperAgentWatcher>(resourceLocator);
1129
- shared_ptr<LoggingAgentWatcher> loggingAgentWatcher =
1130
- make_shared<LoggingAgentWatcher>(resourceLocator);
1131
-
1132
- UPDATE_TRACE_POINT();
1133
- vector<AgentWatcherPtr> watchers;
1134
- vector<AgentWatcherPtr>::iterator it;
1135
- watchers.push_back(helperAgentWatcher);
1136
- if (agentsOptions.get("analytics_server", false).empty()) {
1137
- watchers.push_back(loggingAgentWatcher);
1138
- }
1139
-
1140
- UPDATE_TRACE_POINT();
1141
- for (it = watchers.begin(); it != watchers.end(); it++) {
1142
- try {
1143
- (*it)->start();
1144
- } catch (const std::exception &e) {
1145
- writeArrayMessage(FEEDBACK_FD,
1146
- "Watchdog startup error",
1147
- e.what(),
1148
- NULL);
1149
- forceAllAgentsShutdown(watchers);
1150
- return 1;
1151
- }
1152
- // Allow other exceptions to propagate and crash the watchdog.
468
+ }
469
+ generation = serverInstanceDir->newGeneration(userSwitching, defaultUser,
470
+ defaultGroup, webServerWorkerUid, webServerWorkerGid);
471
+ agentsOptions.set("server_instance_dir", serverInstanceDir->getPath());
472
+ agentsOptions.setInt("generation_number", generation->getNumber());
473
+
474
+ UPDATE_TRACE_POINT();
475
+ serverInstanceDirToucher = new ServerInstanceDirToucher();
476
+
477
+ UPDATE_TRACE_POINT();
478
+ loggingAgentAddress = "unix:" + generation->getPath() + "/logging";
479
+ loggingAgentPassword = randomGenerator->generateAsciiString(64);
480
+ }
481
+
482
+ static void
483
+ initializeAgentWatchers() {
484
+ TRACE_POINT();
485
+ watchers.push_back(make_shared<HelperAgentWatcher>(*resourceLocator));
486
+ watchers.push_back(make_shared<LoggingAgentWatcher>(*resourceLocator));
487
+ }
488
+
489
+ static void
490
+ startAgents() {
491
+ TRACE_POINT();
492
+ foreach (AgentWatcherPtr watcher, watchers) {
493
+ try {
494
+ watcher->start();
495
+ } catch (const std::exception &e) {
496
+ writeArrayMessage(FEEDBACK_FD,
497
+ "Watchdog startup error",
498
+ e.what(),
499
+ NULL);
500
+ forceAllAgentsShutdown(watchers);
501
+ exit(1);
1153
502
  }
1154
- UPDATE_TRACE_POINT();
1155
- for (it = watchers.begin(); it != watchers.end(); it++) {
1156
- try {
1157
- (*it)->startWatching();
1158
- } catch (const std::exception &e) {
1159
- writeArrayMessage(FEEDBACK_FD,
1160
- "Watchdog startup error",
1161
- e.what(),
1162
- NULL);
1163
- forceAllAgentsShutdown(watchers);
1164
- return 1;
1165
- }
1166
- // Allow other exceptions to propagate and crash the watchdog.
503
+ // Allow other exceptions to propagate and crash the watchdog.
504
+ }
505
+ }
506
+
507
+ static void
508
+ startWatchingAgents() {
509
+ foreach (AgentWatcherPtr watcher, watchers) {
510
+ try {
511
+ watcher->startWatching();
512
+ } catch (const std::exception &e) {
513
+ writeArrayMessage(FEEDBACK_FD,
514
+ "Watchdog startup error",
515
+ e.what(),
516
+ NULL);
517
+ forceAllAgentsShutdown(watchers);
518
+ exit(1);
1167
519
  }
1168
-
1169
- UPDATE_TRACE_POINT();
520
+ // Allow other exceptions to propagate and crash the watchdog.
521
+ }
522
+ }
523
+
524
+ static void
525
+ reportAgentsInformation() {
526
+ TRACE_POINT();
527
+ VariantMap report;
528
+
529
+ report
530
+ .set("server_instance_dir", serverInstanceDir->getPath())
531
+ .setInt("generation", generation->getNumber());
532
+
533
+ foreach (AgentWatcherPtr watcher, watchers) {
534
+ watcher->reportAgentsInformation(report);
535
+ }
536
+
537
+ report.writeToFd(FEEDBACK_FD, "Agents information");
538
+ }
539
+
540
+ int
541
+ main(int argc, char *argv[]) {
542
+ initializeBareEssentials(argc, argv);
543
+ P_DEBUG("Starting Watchdog...");
544
+
545
+ try {
546
+ TRACE_POINT();
547
+ initializeOptions();
548
+ initializeWorkingObjects();
549
+ initializeAgentWatchers();
550
+ } catch (const std::exception &e) {
1170
551
  writeArrayMessage(FEEDBACK_FD,
1171
- "Basic startup info",
1172
- serverInstanceDir->getPath().c_str(),
1173
- toString(generation->getNumber()).c_str(),
552
+ "Watchdog startup error",
553
+ e.what(),
1174
554
  NULL);
555
+ return 1;
556
+ }
557
+ // Allow other exceptions to propagate and crash the watchdog.
558
+
559
+ try {
560
+ TRACE_POINT();
561
+ startAgents();
562
+ startWatchingAgents();
563
+ reportAgentsInformation();
564
+ P_INFO("All Phusion Passenger agents started!");
1175
565
 
1176
566
  UPDATE_TRACE_POINT();
1177
- for (it = watchers.begin(); it != watchers.end(); it++) {
1178
- (*it)->sendStartupInfo(FEEDBACK_FD);
1179
- }
1180
-
1181
- UPDATE_TRACE_POINT();
1182
- writeArrayMessage(FEEDBACK_FD, "All agents started", NULL);
1183
- P_DEBUG("All Phusion Passenger agents started!");
1184
-
1185
567
  this_thread::disable_interruption di;
1186
568
  this_thread::disable_syscall_interruption dsi;
1187
- UPDATE_TRACE_POINT();
1188
569
  bool exitGracefully = waitForStarterProcessOrWatchers(watchers);
1189
570
  if (exitGracefully) {
1190
571
  /* Fork a child process which cleans up all the agent processes in
@@ -1199,7 +580,7 @@ main(int argc, char *argv[]) {
1199
580
  AgentWatcher::stopWatching(watchers);
1200
581
  if (exitGracefully) {
1201
582
  UPDATE_TRACE_POINT();
1202
- cleanupAgentsInBackground(watchers);
583
+ cleanupAgentsInBackground(watchers, argv);
1203
584
  return 0;
1204
585
  } else {
1205
586
  UPDATE_TRACE_POINT();
@@ -1209,8 +590,5 @@ main(int argc, char *argv[]) {
1209
590
  } catch (const tracable_exception &e) {
1210
591
  P_ERROR(e.what() << "\n" << e.backtrace());
1211
592
  return 1;
1212
- } catch (const std::exception &e) {
1213
- P_ERROR(e.what());
1214
- return 1;
1215
593
  }
1216
594
  }