passenger 5.1.10 → 5.1.11

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +18 -0
  3. data/Rakefile +20 -17
  4. data/bin/passenger-install-apache2-module +14 -11
  5. data/build/agent.rb +45 -18
  6. data/build/apache2.rb +32 -16
  7. data/build/basics.rb +29 -40
  8. data/build/common_library.rb +70 -54
  9. data/build/cxx_tests.rb +34 -43
  10. data/build/integration_tests.rb +10 -10
  11. data/build/misc.rb +6 -6
  12. data/build/node_tests.rb +1 -2
  13. data/build/oxt_tests.rb +7 -5
  14. data/build/packaging.rb +11 -441
  15. data/build/ruby_extension.rb +1 -1
  16. data/build/ruby_tests.rb +1 -2
  17. data/build/support/cplusplus.rb +6 -5
  18. data/build/support/cxx_dependency_map.rb +357 -833
  19. data/build/support/general.rb +23 -1
  20. data/build/test_basics.rb +3 -28
  21. data/dev/ci/tests/rpm/Jenkinsfile +68 -0
  22. data/dev/ci/tests/rpm/run +63 -0
  23. data/dev/ci/tests/source-packaging/run +1 -1
  24. data/dev/ci/tests/source-packaging/setup +1 -1
  25. data/doc/{Packaging.txt.md → Packaging.md} +0 -0
  26. data/resources/templates/apache2/deployment_example.txt.erb +2 -2
  27. data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
  28. data/resources/templates/nginx/deployment_example.txt.erb +1 -1
  29. data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
  30. data/resources/templates/standalone/server.erb +2 -2
  31. data/src/agent/AgentMain.cpp +0 -4
  32. data/src/agent/Core/CoreMain.cpp +88 -5
  33. data/src/agent/Core/SpawningKit/Spawner.h +2 -1
  34. data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
  35. data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
  36. data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
  37. data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
  38. data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
  39. data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
  40. data/src/agent/Shared/Fundamentals/Utils.h +46 -0
  41. data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
  42. data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
  43. data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
  44. data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
  45. data/src/apache2_module/Hooks.cpp +4 -1
  46. data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
  47. data/src/cxx_supportlib/Constants.h +1 -2
  48. data/src/cxx_supportlib/Crypto.cpp +2 -1
  49. data/src/cxx_supportlib/Hooks.h +16 -37
  50. data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
  51. data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
  52. data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
  53. data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
  54. data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
  55. data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
  56. data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
  57. data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
  58. data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
  59. data/src/cxx_supportlib/Utils.cpp +41 -561
  60. data/src/cxx_supportlib/Utils.h +0 -68
  61. data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
  62. data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
  63. data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
  64. data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
  65. data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
  66. data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
  67. data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
  68. data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
  69. data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
  70. data/src/nginx_module/CacheLocationConfig.c +0 -75
  71. data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
  72. data/src/nginx_module/Configuration.c +0 -1
  73. data/src/nginx_module/Configuration.h +0 -1
  74. data/src/nginx_module/ConfigurationCommands.c +1 -1
  75. data/src/nginx_module/ContentHandler.c +0 -1
  76. data/src/nginx_module/ContentHandler.h +0 -1
  77. data/src/nginx_module/CreateLocationConfig.c +0 -5
  78. data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
  79. data/src/nginx_module/LocationConfig.h +0 -4
  80. data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
  81. data/src/nginx_module/MergeLocationConfig.c +0 -12
  82. data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
  83. data/src/nginx_module/ngx_http_passenger_module.h +0 -1
  84. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  85. data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
  86. data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
  87. data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
  88. data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
  89. data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
  90. data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
  91. data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
  92. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
  93. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
  94. data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
  95. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
  96. data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
  97. data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
  98. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
  99. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
  100. data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
  101. data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
  102. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
  103. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
  104. data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
  105. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
  106. data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
  107. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
  108. metadata +19 -97
  109. data/build/documentation.rb +0 -70
  110. data/doc/CloudLicensingConfiguration.html +0 -172
  111. data/doc/CloudLicensingConfiguration.txt.md +0 -3
  112. data/doc/Packaging.html +0 -488
  113. data/doc/Security of user switching support.idmap.txt +0 -34
  114. data/doc/Security of user switching support.txt +0 -197
  115. data/doc/ServerOptimizationGuide.html +0 -172
  116. data/doc/ServerOptimizationGuide.txt.md +0 -3
  117. data/doc/images/by_sa.png +0 -0
  118. data/doc/images/cloud_licensing_batch_job.png +0 -0
  119. data/doc/images/code_walkthrough.jpg +0 -0
  120. data/doc/images/direct_spawning.png +0 -0
  121. data/doc/images/direct_spawning.svg +0 -251
  122. data/doc/images/glyphicons-halflings-white.png +0 -0
  123. data/doc/images/glyphicons-halflings.png +0 -0
  124. data/doc/images/icons/README +0 -5
  125. data/doc/images/icons/callouts/1.png +0 -0
  126. data/doc/images/icons/callouts/10.png +0 -0
  127. data/doc/images/icons/callouts/11.png +0 -0
  128. data/doc/images/icons/callouts/12.png +0 -0
  129. data/doc/images/icons/callouts/13.png +0 -0
  130. data/doc/images/icons/callouts/14.png +0 -0
  131. data/doc/images/icons/callouts/15.png +0 -0
  132. data/doc/images/icons/callouts/2.png +0 -0
  133. data/doc/images/icons/callouts/3.png +0 -0
  134. data/doc/images/icons/callouts/4.png +0 -0
  135. data/doc/images/icons/callouts/5.png +0 -0
  136. data/doc/images/icons/callouts/6.png +0 -0
  137. data/doc/images/icons/callouts/7.png +0 -0
  138. data/doc/images/icons/callouts/8.png +0 -0
  139. data/doc/images/icons/callouts/9.png +0 -0
  140. data/doc/images/icons/caution.png +0 -0
  141. data/doc/images/icons/example.png +0 -0
  142. data/doc/images/icons/home.png +0 -0
  143. data/doc/images/icons/important.png +0 -0
  144. data/doc/images/icons/next.png +0 -0
  145. data/doc/images/icons/note.png +0 -0
  146. data/doc/images/icons/prev.png +0 -0
  147. data/doc/images/icons/tip.png +0 -0
  148. data/doc/images/icons/up.png +0 -0
  149. data/doc/images/icons/warning.png +0 -0
  150. data/doc/images/many_web_framework_protocols.png +0 -0
  151. data/doc/images/passenger_architecture.png +0 -0
  152. data/doc/images/passenger_architecture.svg +0 -385
  153. data/doc/images/passenger_architecture_overview.png +0 -0
  154. data/doc/images/passenger_core_architecture.png +0 -0
  155. data/doc/images/passenger_nodejs_architecture.svg +0 -558
  156. data/doc/images/phusion_banner.png +0 -0
  157. data/doc/images/rack.png +0 -0
  158. data/doc/images/smart_spawning.png +0 -0
  159. data/doc/images/smart_spawning.svg +0 -323
  160. data/doc/images/spawn_server_architecture.png +0 -0
  161. data/doc/images/spawn_server_architecture.svg +0 -655
  162. data/doc/images/spawning_preparation_work.png +0 -0
  163. data/doc/images/startup_sequence.png +0 -0
  164. data/doc/images/typical_isolated_web_application.png +0 -0
  165. data/doc/images/typical_isolated_web_application.svg +0 -213
  166. data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
  167. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
  168. data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
  169. data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
  170. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
  171. data/doc/users_guide_snippets/deployment_basics.txt +0 -37
  172. data/doc/users_guide_snippets/enterprise_only.txt +0 -1
  173. data/doc/users_guide_snippets/environment_variables.txt +0 -44
  174. data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
  175. data/doc/users_guide_snippets/installation.txt +0 -228
  176. data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
  177. data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
  178. data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
  179. data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
  180. data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
  181. data/doc/users_guide_snippets/since_version.txt +0 -1
  182. data/doc/users_guide_snippets/support_information.txt +0 -8
  183. data/doc/users_guide_snippets/tips.txt +0 -302
  184. data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
  185. data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
  186. data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
  187. data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
  188. data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
  189. data/src/agent/Shared/Base.cpp +0 -1678
  190. data/src/agent/UstRouter/ApiServer.h +0 -292
  191. data/src/agent/UstRouter/Client.h +0 -112
  192. data/src/agent/UstRouter/Controller.h +0 -1309
  193. data/src/agent/UstRouter/LogSink.h +0 -145
  194. data/src/agent/UstRouter/OptionParser.h +0 -180
  195. data/src/agent/UstRouter/RemoteSender.h +0 -853
  196. data/src/agent/UstRouter/RemoteSink.h +0 -145
  197. data/src/agent/UstRouter/Transaction.h +0 -278
  198. data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
  199. data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
  200. data/src/ruby_supportlib/phusion_passenger/platform_info/macos.rb +0 -45
@@ -1,24 +0,0 @@
1
- === Page caching support
2
-
3
- For each HTTP request, Phusion Passenger will automatically look for a corresponding
4
- page cache file, and serve that if it exists. It does this by appending ".html" to
5
- the filename that the URI normally maps to, and checking whether that file exists.
6
- This check occurs after checking whether the original mapped filename exists (as part
7
- of static asset serving). All this is done without the need for special mod_rewrite
8
- rules.
9
-
10
- For example, suppose that the browser requests '/foo/bar'.
11
-
12
- 1. Phusion Passenger will first check whether this URI maps to a static file, i.e.
13
- whether the file 'foo/bar' exists in the web application's 'public' directory.
14
- If it does then Phusion Passenger will serve this file through the web server immediately.
15
- 2. If that doesn't exist, then Phusion Passenger will check whether the file
16
- 'foo/bar.html' exists. If it does then Phusion Passenger will serve this file
17
- through the web server immediately.
18
- 3. If 'foo/bar.html' doesn't exist either, then Phusion Passenger will forward the
19
- request to the underlying web application.
20
-
21
- Note that Phusion Passenger's page caching support doesn't work if your web
22
- application uses a non-standard page cache directory, i.e. if it doesn't cache to
23
- the 'public' directory. In that case you'll need to use mod_rewrite to serve such
24
- page cache files.
@@ -1,10 +0,0 @@
1
- [[relationship_with_ruby]]
2
- === Phusion Passenger and its relationship with Ruby
3
-
4
- ==== How Ruby is used
5
-
6
- This documentation has moved. Please visit https://www.phusionpassenger.com/library/indepth/lightweight_ruby_dependency.html
7
-
8
- ==== When the system has multiple Ruby interpreters
9
-
10
- This documentation has moved. Please visit https://www.phusionpassenger.com/library/indepth/ruby/multiple_rubies.html
@@ -1,9 +0,0 @@
1
- * link:http://groups.google.com/group/phusion-passenger[Community discussion forum] - post a
2
- message here if you're experiencing problems. Support on this forum is provided by the community on a best-effort basis, so a (timely) response is not guaranteed.
3
- * link:https://github.com/phusion/passenger/issues[Issue tracker] - report
4
- bugs here.
5
- * Email support@phusion.nl if you are a link:https://www.phusionpassenger.com/enterprise[Phusion Passenger Enterprise] customer. Please mention your order reference. If you are not an Enterprise customer, we kindly redirect you to the community discussion forum instead.
6
- * link:https://www.phusionpassenger.com/commercial_support[Commercial support contracts] are also available.
7
- * Report security vulnerabilities to security@phusion.nl. We will do our best to respond to you as quickly as we can, so please do not disclose the vulnerability until then.
8
-
9
- Please consult link:https://www.phusionpassenger.com/support[the Phusion Passenger website] for a full list of support resources.
@@ -1,1678 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2017 Phusion Holding B.V.
4
- *
5
- * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
- * trademarks of Phusion Holding B.V.
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in
16
- * all copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
- * THE SOFTWARE.
25
- */
26
- #ifndef _GNU_SOURCE
27
- #define _GNU_SOURCE
28
- #endif
29
-
30
- #include <boost/cstdint.hpp>
31
- #include <oxt/initialize.hpp>
32
- #include <oxt/system_calls.hpp>
33
- #include <oxt/backtrace.hpp>
34
- #include <sys/types.h>
35
- #include <sys/stat.h>
36
- #include <sys/select.h>
37
- #ifdef __linux__
38
- #include <sys/syscall.h>
39
- #include <features.h>
40
- #endif
41
- #include <cstdio>
42
- #include <cstdlib>
43
- #include <cstring>
44
- #include <cerrno>
45
- #include <cassert>
46
- #include <fcntl.h>
47
- #include <poll.h>
48
- #include <unistd.h>
49
- #include <signal.h>
50
- #include <libgen.h>
51
-
52
- #if defined(__APPLE__) || defined(__GNU_LIBRARY__)
53
- #define LIBC_HAS_BACKTRACE_FUNC
54
- #endif
55
- #ifdef LIBC_HAS_BACKTRACE_FUNC
56
- #include <execinfo.h>
57
- #endif
58
-
59
- #include <string>
60
- #include <vector>
61
-
62
- #include <Shared/Base.h>
63
- #include <Constants.h>
64
- #include <Exceptions.h>
65
- #include <LoggingKit/LoggingKit.h>
66
- #include <LoggingKit/Context.h>
67
- #include <ResourceLocator.h>
68
- #include <Utils.h>
69
- #include <Utils/SystemTime.h>
70
- #include <Utils/StrIntUtils.h>
71
- #ifdef __linux__
72
- #include <ResourceLocator.h>
73
- #endif
74
-
75
- #include <jsoncpp/json.h>
76
-
77
- namespace Passenger {
78
-
79
-
80
- using namespace std;
81
-
82
-
83
- struct AbortHandlerState {
84
- pid_t pid;
85
- int signo;
86
- siginfo_t *info;
87
- char messagePrefix[32];
88
- char messageBuf[1024];
89
- };
90
-
91
- typedef void (*Callback)(AbortHandlerState &state, void *userData);
92
-
93
-
94
- #define IGNORE_SYSCALL_RESULT(code) \
95
- do { \
96
- int _ret = code; \
97
- (void) _ret; \
98
- } while (false)
99
-
100
-
101
- static bool _feedbackFdAvailable = false;
102
- static const char digits[] = {
103
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
104
- };
105
- static const char hex_chars[] = "0123456789abcdef";
106
-
107
- static bool shouldDumpWithCrashWatch = true;
108
- static bool beepOnAbort = false;
109
- static bool stopOnAbort = false;
110
-
111
- // Pre-allocate an alternative stack for use in signal handlers in case
112
- // the normal stack isn't usable.
113
- static char *alternativeStack;
114
- static unsigned int alternativeStackSize;
115
-
116
- static volatile unsigned int abortHandlerCalled = 0;
117
- static unsigned int randomSeed = 0;
118
- static char **origArgv = NULL;
119
- static const char *rubyLibDir = NULL;
120
- static const char *passengerRoot = NULL;
121
- static const char *defaultRuby = DEFAULT_RUBY;
122
- static const char *backtraceSanitizerCommand = NULL;
123
- static bool backtraceSanitizerPassProgramInfo = true;
124
- static const char *crashWatch = NULL;
125
- static DiagnosticsDumper customDiagnosticsDumper = NULL;
126
- static void *customDiagnosticsDumperUserData;
127
-
128
- // We preallocate a few pipes during startup which we will close in the
129
- // crash handler. This way we can be sure that when the crash handler
130
- // calls pipe() it won't fail with "Too many files".
131
- static int emergencyPipe1[2] = { -1, -1 };
132
- static int emergencyPipe2[2] = { -1, -1 };
133
-
134
-
135
- static void
136
- ignoreSigpipe() {
137
- struct sigaction action;
138
- action.sa_handler = SIG_IGN;
139
- action.sa_flags = 0;
140
- sigemptyset(&action.sa_mask);
141
- sigaction(SIGPIPE, &action, NULL);
142
- }
143
-
144
- const char *
145
- getEnvString(const char *name, const char *defaultValue) {
146
- const char *value = getenv(name);
147
- if (value != NULL && *value != '\0') {
148
- return value;
149
- } else {
150
- return defaultValue;
151
- }
152
- }
153
-
154
- bool
155
- hasEnvOption(const char *name, bool defaultValue) {
156
- const char *value = getEnvString(name);
157
- if (value != NULL) {
158
- return strcmp(value, "yes") == 0
159
- || strcmp(value, "y") == 0
160
- || strcmp(value, "1") == 0
161
- || strcmp(value, "on") == 0
162
- || strcmp(value, "true") == 0;
163
- } else {
164
- return defaultValue;
165
- }
166
- }
167
-
168
- // When we're in a crash handler, there's nothing we can do if we fail to
169
- // write to stderr, so we ignore its return value and we ignore compiler
170
- // warnings about ignoring that.
171
- static void
172
- write_nowarn(int fd, const void *buf, size_t n) {
173
- ssize_t ret = write(fd, buf, n);
174
- (void) ret;
175
- }
176
-
177
- // No idea whether strlen() is async signal safe, but let's not risk it
178
- // and write our own version instead that's guaranteed to be safe.
179
- static size_t
180
- safeStrlen(const char *str) {
181
- size_t size = 0;
182
- while (*str != '\0') {
183
- str++;
184
- size++;
185
- }
186
- return size;
187
- }
188
-
189
- // Async-signal safe way to print to stderr.
190
- static void
191
- safePrintErr(const char *message) {
192
- write_nowarn(STDERR_FILENO, message, strlen(message));
193
- }
194
-
195
- // Must be async signal safe.
196
- static char *
197
- appendText(char *buf, const char *text) {
198
- size_t len = safeStrlen(text);
199
- strcpy(buf, text);
200
- return buf + len;
201
- }
202
-
203
- // Must be async signal safe.
204
- static void
205
- reverse(char *str, size_t len) {
206
- char *p1, *p2;
207
- if (*str == '\0') {
208
- return;
209
- }
210
- for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) {
211
- *p1 ^= *p2;
212
- *p2 ^= *p1;
213
- *p1 ^= *p2;
214
- }
215
- }
216
-
217
- // Must be async signal safe.
218
- static char *
219
- appendULL(char *buf, unsigned long long value) {
220
- unsigned long long remainder = value;
221
- unsigned int size = 0;
222
-
223
- do {
224
- buf[size] = digits[remainder % 10];
225
- remainder = remainder / 10;
226
- size++;
227
- } while (remainder != 0);
228
-
229
- reverse(buf, size);
230
- return buf + size;
231
- }
232
-
233
- // Must be async signal safe.
234
- template<typename IntegerType>
235
- static char *
236
- appendIntegerAsHex(char *buf, IntegerType value) {
237
- IntegerType remainder = value;
238
- unsigned int size = 0;
239
-
240
- do {
241
- buf[size] = hex_chars[remainder % 16];
242
- remainder = remainder / 16;
243
- size++;
244
- } while (remainder != 0);
245
-
246
- reverse(buf, size);
247
- return buf + size;
248
- }
249
-
250
- // Must be async signal safe.
251
- static char *
252
- appendPointerAsString(char *buf, void *pointer) {
253
- return appendIntegerAsHex(appendText(buf, "0x"), (boost::uintptr_t) pointer);
254
- }
255
-
256
- static char *
257
- appendSignalName(char *buf, int signo) {
258
- switch (signo) {
259
- case SIGABRT:
260
- buf = appendText(buf, "SIGABRT");
261
- break;
262
- case SIGSEGV:
263
- buf = appendText(buf, "SIGSEGV");
264
- break;
265
- case SIGBUS:
266
- buf = appendText(buf, "SIGBUS");
267
- break;
268
- case SIGFPE:
269
- buf = appendText(buf, "SIGFPE");
270
- break;
271
- case SIGILL:
272
- buf = appendText(buf, "SIGILL");
273
- break;
274
- default:
275
- return appendULL(buf, (unsigned long long) signo);
276
- }
277
- buf = appendText(buf, "(");
278
- buf = appendULL(buf, (unsigned long long) signo);
279
- buf = appendText(buf, ")");
280
- return buf;
281
- }
282
-
283
- #define SI_CODE_HANDLER(name) \
284
- case name: \
285
- buf = appendText(buf, #name); \
286
- break
287
-
288
- // Must be async signal safe.
289
- static char *
290
- appendSignalReason(char *buf, siginfo_t *info) {
291
- bool handled = true;
292
-
293
- switch (info->si_code) {
294
- SI_CODE_HANDLER(SI_USER);
295
- #ifdef SI_KERNEL
296
- SI_CODE_HANDLER(SI_KERNEL);
297
- #endif
298
- SI_CODE_HANDLER(SI_QUEUE);
299
- SI_CODE_HANDLER(SI_TIMER);
300
- #ifdef SI_ASYNCIO
301
- SI_CODE_HANDLER(SI_ASYNCIO);
302
- #endif
303
- #ifdef SI_MESGQ
304
- SI_CODE_HANDLER(SI_MESGQ);
305
- #endif
306
- #ifdef SI_SIGIO
307
- SI_CODE_HANDLER(SI_SIGIO);
308
- #endif
309
- #ifdef SI_TKILL
310
- SI_CODE_HANDLER(SI_TKILL);
311
- #endif
312
- default:
313
- switch (info->si_signo) {
314
- case SIGSEGV:
315
- switch (info->si_code) {
316
- #ifdef SEGV_MAPERR
317
- SI_CODE_HANDLER(SEGV_MAPERR);
318
- #endif
319
- #ifdef SEGV_ACCERR
320
- SI_CODE_HANDLER(SEGV_ACCERR);
321
- #endif
322
- default:
323
- handled = false;
324
- break;
325
- }
326
- break;
327
- case SIGBUS:
328
- switch (info->si_code) {
329
- #ifdef BUS_ADRALN
330
- SI_CODE_HANDLER(BUS_ADRALN);
331
- #endif
332
- #ifdef BUS_ADRERR
333
- SI_CODE_HANDLER(BUS_ADRERR);
334
- #endif
335
- #ifdef BUS_OBJERR
336
- SI_CODE_HANDLER(BUS_OBJERR);
337
- #endif
338
- default:
339
- handled = false;
340
- break;
341
- }
342
- break;
343
- default:
344
- handled = false;
345
- break;
346
- }
347
- if (!handled) {
348
- buf = appendText(buf, "#");
349
- buf = appendULL(buf, (unsigned long long) info->si_code);
350
- }
351
- break;
352
- }
353
-
354
- if (info->si_code <= 0) {
355
- buf = appendText(buf, ", signal sent by PID ");
356
- buf = appendULL(buf, (unsigned long long) info->si_pid);
357
- buf = appendText(buf, " with UID ");
358
- buf = appendULL(buf, (unsigned long long) info->si_uid);
359
- }
360
-
361
- buf = appendText(buf, ", si_addr=");
362
- buf = appendPointerAsString(buf, info->si_addr);
363
-
364
- return buf;
365
- }
366
-
367
- static int
368
- runInSubprocessWithTimeLimit(AbortHandlerState &state, Callback callback, void *userData, int timeLimit) {
369
- char *end;
370
- pid_t child;
371
- int p[2], e;
372
-
373
- if (pipe(p) == -1) {
374
- e = errno;
375
- end = state.messageBuf;
376
- end = appendText(end, "Could not create subprocess: pipe() failed with errno=");
377
- end = appendULL(end, e);
378
- end = appendText(end, "\n");
379
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
380
- return -1;
381
- }
382
-
383
- child = asyncFork();
384
- if (child == 0) {
385
- close(p[0]);
386
- callback(state, userData);
387
- _exit(0);
388
- return -1;
389
-
390
- } else if (child == -1) {
391
- e = errno;
392
- close(p[0]);
393
- close(p[1]);
394
- end = state.messageBuf;
395
- end = appendText(end, "Could not create subprocess: fork() failed with errno=");
396
- end = appendULL(end, e);
397
- end = appendText(end, "\n");
398
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
399
- return -1;
400
-
401
- } else {
402
- int status;
403
- close(p[1]);
404
-
405
- // We give the child process a time limit. If it doesn't succeed in
406
- // exiting within the time limit, we assume that it has frozen
407
- // and we kill it.
408
- struct pollfd fd;
409
- fd.fd = p[0];
410
- fd.events = POLLIN | POLLHUP | POLLERR;
411
- if (poll(&fd, 1, timeLimit) <= 0) {
412
- kill(child, SIGKILL);
413
- safePrintErr("Could not run child process: it did not exit in time\n");
414
- }
415
- close(p[0]);
416
- if (waitpid(child, &status, 0) == child) {
417
- return status;
418
- } else {
419
- return -1;
420
- }
421
- }
422
- }
423
-
424
- static void
425
- dumpFileDescriptorInfoWithLsof(AbortHandlerState &state, void *userData) {
426
- char *end;
427
-
428
- end = state.messageBuf;
429
- end = appendULL(end, state.pid);
430
- *end = '\0';
431
-
432
- closeAllFileDescriptors(2, true);
433
-
434
- execlp("lsof", "lsof", "-p", state.messageBuf, "-nP", (const char * const) 0);
435
-
436
- end = state.messageBuf;
437
- end = appendText(end, "ERROR: cannot execute command 'lsof': errno=");
438
- end = appendULL(end, errno);
439
- end = appendText(end, "\n");
440
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
441
- _exit(1);
442
- }
443
-
444
- static void
445
- dumpFileDescriptorInfoWithLs(AbortHandlerState &state, char *end) {
446
- pid_t pid;
447
- int status;
448
-
449
- pid = asyncFork();
450
- if (pid == 0) {
451
- closeAllFileDescriptors(2, true);
452
- // The '-v' is for natural sorting on Linux. On BSD -v means something else but it's harmless.
453
- execlp("ls", "ls", "-lv", state.messageBuf, (const char * const) 0);
454
- _exit(1);
455
- } else if (pid == -1) {
456
- safePrintErr("ERROR: Could not fork a process to dump file descriptor information!\n");
457
- } else if (waitpid(pid, &status, 0) != pid || status != 0) {
458
- safePrintErr("ERROR: Could not run 'ls' to dump file descriptor information!\n");
459
- }
460
- }
461
-
462
- static void
463
- dumpFileDescriptorInfo(AbortHandlerState &state) {
464
- char *messageBuf = state.messageBuf;
465
- char *end;
466
- struct stat buf;
467
- int status;
468
-
469
- end = messageBuf;
470
- end = appendText(end, state.messagePrefix);
471
- end = appendText(end, " ] Open files and file descriptors:\n");
472
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
473
-
474
- status = runInSubprocessWithTimeLimit(state, dumpFileDescriptorInfoWithLsof, NULL, 4000);
475
-
476
- if (status != 0) {
477
- safePrintErr("Falling back to another mechanism for dumping file descriptors.\n");
478
-
479
- end = messageBuf;
480
- end = appendText(end, "/proc/");
481
- end = appendULL(end, state.pid);
482
- end = appendText(end, "/fd");
483
- *end = '\0';
484
- if (stat(messageBuf, &buf) == 0) {
485
- dumpFileDescriptorInfoWithLs(state, end + 1);
486
- } else {
487
- end = messageBuf;
488
- end = appendText(end, "/dev/fd");
489
- *end = '\0';
490
- if (stat(messageBuf, &buf) == 0) {
491
- dumpFileDescriptorInfoWithLs(state, end + 1);
492
- } else {
493
- end = messageBuf;
494
- end = appendText(end, "ERROR: No other file descriptor dumping mechanism on current platform detected.\n");
495
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
496
- }
497
- }
498
- }
499
- }
500
-
501
- static void
502
- dumpWithCrashWatch(AbortHandlerState &state) {
503
- char *messageBuf = state.messageBuf;
504
- const char *pidStr = messageBuf;
505
- char *end = messageBuf;
506
- end = appendULL(end, (unsigned long long) state.pid);
507
- *end = '\0';
508
-
509
- pid_t child = asyncFork();
510
- if (child == 0) {
511
- closeAllFileDescriptors(2, true);
512
- execlp(defaultRuby, defaultRuby, crashWatch, rubyLibDir,
513
- passengerRoot, "--dump", pidStr, (char * const) 0);
514
- int e = errno;
515
- end = messageBuf;
516
- end = appendText(end, "crash-watch is could not be executed! ");
517
- end = appendText(end, "(execlp() returned errno=");
518
- end = appendULL(end, e);
519
- end = appendText(end, ") Please check your file permissions or something.\n");
520
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
521
- _exit(1);
522
-
523
- } else if (child == -1) {
524
- int e = errno;
525
- end = messageBuf;
526
- end = appendText(end, "Could not execute crash-watch: fork() failed with errno=");
527
- end = appendULL(end, e);
528
- end = appendText(end, "\n");
529
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
530
-
531
- } else {
532
- waitpid(child, NULL, 0);
533
- }
534
- }
535
-
536
- #ifdef LIBC_HAS_BACKTRACE_FUNC
537
- static void
538
- dumpBacktrace(AbortHandlerState &state, void *userData) {
539
- void *backtraceStore[512];
540
- int frames = backtrace(backtraceStore, sizeof(backtraceStore) / sizeof(void *));
541
- char *end = state.messageBuf;
542
- end = appendText(end, "--------------------------------------\n");
543
- end = appendText(end, "[ pid=");
544
- end = appendULL(end, (unsigned long long) state.pid);
545
- end = appendText(end, " ] Backtrace with ");
546
- end = appendULL(end, (unsigned long long) frames);
547
- end = appendText(end, " frames:\n");
548
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
549
-
550
- if (backtraceSanitizerCommand != NULL) {
551
- int p[2];
552
- if (pipe(p) == -1) {
553
- int e = errno;
554
- end = state.messageBuf;
555
- end = appendText(end, "Could not dump diagnostics through backtrace sanitizer: pipe() failed with errno=");
556
- end = appendULL(end, e);
557
- end = appendText(end, "\n");
558
- end = appendText(end, "Falling back to writing to stderr directly...\n");
559
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
560
- backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
561
- return;
562
- }
563
-
564
- pid_t pid = asyncFork();
565
- if (pid == 0) {
566
- const char *pidStr = end = state.messageBuf;
567
- end = appendULL(end, (unsigned long long) state.pid);
568
- *end = '\0';
569
- end++;
570
-
571
- close(p[1]);
572
- dup2(p[0], STDIN_FILENO);
573
- closeAllFileDescriptors(2, true);
574
-
575
- char *command = end;
576
- end = appendText(end, "exec ");
577
- end = appendText(end, backtraceSanitizerCommand);
578
- if (backtraceSanitizerPassProgramInfo) {
579
- end = appendText(end, " \"");
580
- end = appendText(end, origArgv[0]);
581
- end = appendText(end, "\" ");
582
- end = appendText(end, pidStr);
583
- }
584
- *end = '\0';
585
- end++;
586
- execlp("/bin/sh", "/bin/sh", "-c", command, (const char * const) 0);
587
-
588
- end = state.messageBuf;
589
- end = appendText(end, "ERROR: cannot execute '");
590
- end = appendText(end, backtraceSanitizerCommand);
591
- end = appendText(end, "' for sanitizing the backtrace, trying 'cat'...\n");
592
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
593
- execlp("cat", "cat", (const char * const) 0);
594
- execlp("/bin/cat", "cat", (const char * const) 0);
595
- execlp("/usr/bin/cat", "cat", (const char * const) 0);
596
- safePrintErr("ERROR: cannot execute 'cat'\n");
597
- _exit(1);
598
-
599
- } else if (pid == -1) {
600
- close(p[0]);
601
- close(p[1]);
602
- int e = errno;
603
- end = state.messageBuf;
604
- end = appendText(end, "Could not dump diagnostics through backtrace sanitizer: fork() failed with errno=");
605
- end = appendULL(end, e);
606
- end = appendText(end, "\n");
607
- end = appendText(end, "Falling back to writing to stderr directly...\n");
608
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
609
- backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
610
-
611
- } else {
612
- int status = -1;
613
-
614
- close(p[0]);
615
- backtrace_symbols_fd(backtraceStore, frames, p[1]);
616
- close(p[1]);
617
- if (waitpid(pid, &status, 0) == -1 || status != 0) {
618
- end = state.messageBuf;
619
- end = appendText(end, "ERROR: cannot execute '");
620
- end = appendText(end, backtraceSanitizerCommand);
621
- end = appendText(end, "' for sanitizing the backtrace, writing to stderr directly...\n");
622
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
623
- backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
624
- }
625
- }
626
-
627
- } else {
628
- backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
629
- }
630
- }
631
- #endif
632
-
633
- static void
634
- runCustomDiagnosticsDumper(AbortHandlerState &state, void *userData) {
635
- customDiagnosticsDumper(customDiagnosticsDumperUserData);
636
- }
637
-
638
- // This function is performed in a child process.
639
- static void
640
- dumpDiagnostics(AbortHandlerState &state) {
641
- char *messageBuf = state.messageBuf;
642
- char *end;
643
- pid_t pid;
644
- int status;
645
-
646
- end = messageBuf;
647
- end = appendText(end, state.messagePrefix);
648
- end = appendText(end, " ] Date, uname and ulimits:\n");
649
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
650
-
651
- // Dump human-readable time string and string.
652
- pid = asyncFork();
653
- if (pid == 0) {
654
- closeAllFileDescriptors(2, true);
655
- execlp("date", "date", (const char * const) 0);
656
- _exit(1);
657
- } else if (pid == -1) {
658
- safePrintErr("ERROR: Could not fork a process to dump the time!\n");
659
- } else if (waitpid(pid, &status, 0) != pid || status != 0) {
660
- safePrintErr("ERROR: Could not run 'date'!\n");
661
- }
662
-
663
- // Dump system uname.
664
- pid = asyncFork();
665
- if (pid == 0) {
666
- closeAllFileDescriptors(2, true);
667
- execlp("uname", "uname", "-mprsv", (const char * const) 0);
668
- _exit(1);
669
- } else if (pid == -1) {
670
- safePrintErr("ERROR: Could not fork a process to dump the uname!\n");
671
- } else if (waitpid(pid, &status, 0) != pid || status != 0) {
672
- safePrintErr("ERROR: Could not run 'uname -mprsv'!\n");
673
- }
674
-
675
- // Dump ulimit.
676
- pid = asyncFork();
677
- if (pid == 0) {
678
- closeAllFileDescriptors(2, true);
679
- execlp("ulimit", "ulimit", "-a", (const char * const) 0);
680
- // On Linux 'ulimit' is a shell builtin, not a command.
681
- execlp("/bin/sh", "/bin/sh", "-c", "ulimit -a", (const char * const) 0);
682
- _exit(1);
683
- } else if (pid == -1) {
684
- safePrintErr("ERROR: Could not fork a process to dump the ulimit!\n");
685
- } else if (waitpid(pid, &status, 0) != pid || status != 0) {
686
- safePrintErr("ERROR: Could not run 'ulimit -a'!\n");
687
- }
688
-
689
- end = messageBuf;
690
- end = appendText(end, state.messagePrefix);
691
- end = appendText(end, " ] " PROGRAM_NAME " version: " PASSENGER_VERSION "\n");
692
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
693
-
694
- if (LoggingKit::lastAssertionFailure.filename != NULL) {
695
- end = messageBuf;
696
- end = appendText(end, state.messagePrefix);
697
- end = appendText(end, " ] Last assertion failure: (");
698
- end = appendText(end, LoggingKit::lastAssertionFailure.expression);
699
- end = appendText(end, "), ");
700
- if (LoggingKit::lastAssertionFailure.function != NULL) {
701
- end = appendText(end, "function ");
702
- end = appendText(end, LoggingKit::lastAssertionFailure.function);
703
- end = appendText(end, ", ");
704
- }
705
- end = appendText(end, "file ");
706
- end = appendText(end, LoggingKit::lastAssertionFailure.filename);
707
- end = appendText(end, ", line ");
708
- end = appendULL(end, LoggingKit::lastAssertionFailure.line);
709
- end = appendText(end, ".\n");
710
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
711
- }
712
-
713
- // It is important that writing the message and the backtrace are two
714
- // seperate operations because it's not entirely clear whether the
715
- // latter is async signal safe and thus can crash.
716
- end = messageBuf;
717
- end = appendText(end, state.messagePrefix);
718
- #ifdef LIBC_HAS_BACKTRACE_FUNC
719
- end = appendText(end, " ] libc backtrace available!\n");
720
- #else
721
- end = appendText(end, " ] libc backtrace not available.\n");
722
- #endif
723
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
724
-
725
- #ifdef LIBC_HAS_BACKTRACE_FUNC
726
- runInSubprocessWithTimeLimit(state, dumpBacktrace, NULL, 4000);
727
- #endif
728
-
729
- safePrintErr("--------------------------------------\n");
730
-
731
- if (customDiagnosticsDumper != NULL) {
732
- end = messageBuf;
733
- end = appendText(end, state.messagePrefix);
734
- end = appendText(end, " ] Dumping additional diagnostical information...\n");
735
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
736
- safePrintErr("--------------------------------------\n");
737
- runInSubprocessWithTimeLimit(state, runCustomDiagnosticsDumper, NULL, 2000);
738
- safePrintErr("--------------------------------------\n");
739
- }
740
-
741
- dumpFileDescriptorInfo(state);
742
- safePrintErr("--------------------------------------\n");
743
-
744
- if (shouldDumpWithCrashWatch) {
745
- end = messageBuf;
746
- end = appendText(end, state.messagePrefix);
747
- #ifdef LIBC_HAS_BACKTRACE_FUNC
748
- end = appendText(end, " ] Dumping a more detailed backtrace with crash-watch...\n");
749
- #else
750
- end = appendText(end, " ] Dumping a backtrace with crash-watch...\n");
751
- #endif
752
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
753
- dumpWithCrashWatch(state);
754
- } else {
755
- write_nowarn(STDERR_FILENO, "\n", 1);
756
- }
757
- }
758
-
759
- static bool
760
- createCrashLogFile(char *filename, time_t t) {
761
- char *end = filename;
762
- end = appendText(end, "/var/tmp/passenger-crash-log.");
763
- end = appendULL(end, (unsigned long long) t);
764
- *end = '\0';
765
-
766
- int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
767
- if (fd == -1) {
768
- end = filename;
769
- end = appendText(end, "/tmp/passenger-crash-log.");
770
- end = appendULL(end, (unsigned long long) t);
771
- *end = '\0';
772
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
773
- }
774
- if (fd == -1) {
775
- *filename = '\0';
776
- return false;
777
- } else {
778
- close(fd);
779
- return true;
780
- }
781
- }
782
-
783
- static void
784
- forkAndRedirectToTee(char *filename) {
785
- pid_t pid;
786
- int p[2];
787
-
788
- if (pipe(p) == -1) {
789
- // Signal error condition.
790
- *filename = '\0';
791
- return;
792
- }
793
-
794
- pid = asyncFork();
795
- if (pid == 0) {
796
- close(p[1]);
797
- dup2(p[0], STDIN_FILENO);
798
- execlp("tee", "tee", filename, (const char * const) 0);
799
- execlp("/usr/bin/tee", "tee", filename, (const char * const) 0);
800
- execlp("cat", "cat", (const char * const) 0);
801
- execlp("/bin/cat", "cat", (const char * const) 0);
802
- execlp("/usr/bin/cat", "cat", (const char * const) 0);
803
- safePrintErr("ERROR: cannot execute 'tee' or 'cat'; crash log will be lost!\n");
804
- _exit(1);
805
- } else if (pid == -1) {
806
- safePrintErr("ERROR: cannot fork a process for executing 'tee'\n");
807
- *filename = '\0';
808
- } else {
809
- close(p[0]);
810
- dup2(p[1], STDOUT_FILENO);
811
- dup2(p[1], STDERR_FILENO);
812
- }
813
- }
814
-
815
- static void
816
- abortHandler(int signo, siginfo_t *info, void *ctx) {
817
- AbortHandlerState state;
818
- state.pid = getpid();
819
- state.signo = signo;
820
- state.info = info;
821
- pid_t child;
822
- time_t t = time(NULL);
823
- char crashLogFile[256];
824
-
825
- abortHandlerCalled++;
826
- if (abortHandlerCalled > 1) {
827
- // The abort handler itself crashed!
828
- char *end = state.messageBuf;
829
- end = appendText(end, "[ origpid=");
830
- end = appendULL(end, (unsigned long long) state.pid);
831
- end = appendText(end, ", pid=");
832
- end = appendULL(end, (unsigned long long) getpid());
833
- end = appendText(end, ", timestamp=");
834
- end = appendULL(end, (unsigned long long) t);
835
- if (abortHandlerCalled == 2) {
836
- // This is the first time it crashed.
837
- end = appendText(end, " ] Abort handler crashed! signo=");
838
- end = appendSignalName(end, state.signo);
839
- end = appendText(end, ", reason=");
840
- end = appendSignalReason(end, state.info);
841
- end = appendText(end, "\n");
842
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
843
- // Run default signal handler.
844
- raise(signo);
845
- } else {
846
- // This is the second time it crashed, meaning it failed to
847
- // invoke the default signal handler to abort the process!
848
- end = appendText(end, " ] Abort handler crashed again! Force exiting this time. signo=");
849
- end = appendSignalName(end, state.signo);
850
- end = appendText(end, ", reason=");
851
- end = appendSignalReason(end, state.info);
852
- end = appendText(end, "\n");
853
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
854
- _exit(1);
855
- }
856
- return;
857
- }
858
-
859
- if (emergencyPipe1[0] != -1) {
860
- close(emergencyPipe1[0]);
861
- }
862
- if (emergencyPipe1[1] != -1) {
863
- close(emergencyPipe1[1]);
864
- }
865
- if (emergencyPipe2[0] != -1) {
866
- close(emergencyPipe2[0]);
867
- }
868
- if (emergencyPipe2[1] != -1) {
869
- close(emergencyPipe2[1]);
870
- }
871
- emergencyPipe1[0] = emergencyPipe1[1] = -1;
872
- emergencyPipe2[0] = emergencyPipe2[1] = -1;
873
-
874
- /* We want to dump the entire crash log to both stderr and a log file.
875
- * We use 'tee' for this.
876
- */
877
- if (createCrashLogFile(crashLogFile, t)) {
878
- forkAndRedirectToTee(crashLogFile);
879
- }
880
-
881
- char *end = state.messagePrefix;
882
- end = appendText(end, "[ pid=");
883
- end = appendULL(end, (unsigned long long) state.pid);
884
- *end = '\0';
885
-
886
- end = state.messageBuf;
887
- end = appendText(end, state.messagePrefix);
888
- end = appendText(end, ", timestamp=");
889
- end = appendULL(end, (unsigned long long) t);
890
- end = appendText(end, " ] Process aborted! signo=");
891
- end = appendSignalName(end, state.signo);
892
- end = appendText(end, ", reason=");
893
- end = appendSignalReason(end, state.info);
894
- end = appendText(end, ", randomSeed=");
895
- end = appendULL(end, (unsigned long long) randomSeed);
896
- end = appendText(end, "\n");
897
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
898
-
899
- end = state.messageBuf;
900
- if (*crashLogFile != '\0') {
901
- end = appendText(end, state.messagePrefix);
902
- end = appendText(end, " ] Crash log dumped to ");
903
- end = appendText(end, crashLogFile);
904
- end = appendText(end, "\n");
905
- } else {
906
- end = appendText(end, state.messagePrefix);
907
- end = appendText(end, " ] Could not create crash log file, so dumping to stderr only.\n");
908
- }
909
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
910
-
911
- if (beepOnAbort) {
912
- end = state.messageBuf;
913
- end = appendText(end, state.messagePrefix);
914
- end = appendText(end, " ] PASSENGER_BEEP_ON_ABORT on, executing beep...\n");
915
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
916
-
917
- child = asyncFork();
918
- if (child == 0) {
919
- closeAllFileDescriptors(2, true);
920
- #ifdef __APPLE__
921
- execlp("osascript", "osascript", "-e", "beep 2", (const char * const) 0);
922
- safePrintErr("Cannot execute 'osascript' command\n");
923
- #else
924
- execlp("beep", "beep", (const char * const) 0);
925
- safePrintErr("Cannot execute 'beep' command\n");
926
- #endif
927
- _exit(1);
928
-
929
- } else if (child == -1) {
930
- int e = errno;
931
- end = state.messageBuf;
932
- end = appendText(end, state.messagePrefix);
933
- end = appendText(end, " ] Could fork a child process for invoking a beep: fork() failed with errno=");
934
- end = appendULL(end, e);
935
- end = appendText(end, "\n");
936
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
937
- }
938
- }
939
-
940
- if (stopOnAbort) {
941
- end = state.messageBuf;
942
- end = appendText(end, state.messagePrefix);
943
- end = appendText(end, " ] PASSENGER_STOP_ON_ABORT on, so process stopped. Send SIGCONT when you want to continue.\n");
944
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
945
- raise(SIGSTOP);
946
- }
947
-
948
- // It isn't safe to call any waiting functions in this signal handler,
949
- // not even read() and waitpid() even though they're async signal safe.
950
- // So we fork a child process and let it dump as much diagnostics as possible
951
- // instead of doing it in this process.
952
- child = asyncFork();
953
- if (child == 0) {
954
- // Sleep for a short while to allow the parent process to raise SIGSTOP.
955
- // usleep() and nanosleep() aren't async signal safe so we use select()
956
- // instead.
957
- struct timeval tv;
958
- tv.tv_sec = 0;
959
- tv.tv_usec = 100000;
960
- select(0, NULL, NULL, NULL, &tv);
961
-
962
- resetSignalHandlersAndMask();
963
-
964
- child = asyncFork();
965
- if (child == 0) {
966
- // OS X: for some reason the SIGPIPE handler may be reset to default after forking.
967
- // Later in this program we're going to pipe backtrace_symbols_fd() into the backtrace
968
- // sanitizer, which may fail, and we don't want the diagnostics process to crash
969
- // with SIGPIPE as a result, so we ignore SIGPIPE again.
970
- ignoreSigpipe();
971
- dumpDiagnostics(state);
972
- // The child process may or may or may not resume the original process.
973
- // We do it ourselves just to be sure.
974
- kill(state.pid, SIGCONT);
975
- _exit(0);
976
-
977
- } else if (child == -1) {
978
- int e = errno;
979
- end = state.messageBuf;
980
- end = appendText(end, state.messagePrefix);
981
- end = appendText(end, "] Could fork a child process for dumping diagnostics: fork() failed with errno=");
982
- end = appendULL(end, e);
983
- end = appendText(end, "\n");
984
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
985
- _exit(1);
986
-
987
- } else {
988
- // Exit immediately so that child process is adopted by init process.
989
- _exit(0);
990
- }
991
-
992
- } else if (child == -1) {
993
- int e = errno;
994
- end = state.messageBuf;
995
- end = appendText(end, state.messagePrefix);
996
- end = appendText(end, " ] Could fork a child process for dumping diagnostics: fork() failed with errno=");
997
- end = appendULL(end, e);
998
- end = appendText(end, "\n");
999
- write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
1000
-
1001
- } else {
1002
- raise(SIGSTOP);
1003
- // Will continue after the child process has done its job.
1004
- }
1005
-
1006
- // Run default signal handler.
1007
- raise(signo);
1008
- }
1009
-
1010
- /*
1011
- * Override assert() to add more features and to fix bugs. We save the information
1012
- * of the last assertion failure in a global variable so that we can print it
1013
- * to the crash diagnostics report.
1014
- */
1015
- #if defined(__GLIBC__)
1016
- extern "C" __attribute__ ((__noreturn__))
1017
- void
1018
- __assert_fail(__const char *__assertion, __const char *__file,
1019
- unsigned int __line, __const char *__function)
1020
- {
1021
- LoggingKit::lastAssertionFailure.filename = __file;
1022
- LoggingKit::lastAssertionFailure.line = __line;
1023
- LoggingKit::lastAssertionFailure.function = __function;
1024
- LoggingKit::lastAssertionFailure.expression = __assertion;
1025
- fprintf(stderr, "Assertion failed! %s:%u: %s: %s\n", __file, __line, __function, __assertion);
1026
- fflush(stderr);
1027
- abort();
1028
- }
1029
-
1030
- #elif defined(__APPLE__)
1031
- /* On OS X, raise() and abort() unfortunately send SIGABRT to the main thread,
1032
- * causing the original backtrace to be lost in the signal handler.
1033
- * We work around this for anything in the same linkage unit by just definin
1034
- * our own versions of the assert handler and abort.
1035
- */
1036
-
1037
- #include <pthread.h>
1038
-
1039
- extern "C" int
1040
- raise(int sig) {
1041
- return pthread_kill(pthread_self(), sig);
1042
- }
1043
-
1044
- extern "C" void
1045
- __assert_rtn(const char *func, const char *file, int line, const char *expr) {
1046
- LoggingKit::lastAssertionFailure.filename = file;
1047
- LoggingKit::lastAssertionFailure.line = line;
1048
- LoggingKit::lastAssertionFailure.function = func;
1049
- LoggingKit::lastAssertionFailure.expression = expr;
1050
- if (func) {
1051
- fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n",
1052
- expr, func, file, line);
1053
- } else {
1054
- fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n",
1055
- expr, file, line);
1056
- }
1057
- fflush(stderr);
1058
- abort();
1059
- }
1060
-
1061
- extern "C" void
1062
- abort() {
1063
- sigset_t set;
1064
- sigemptyset(&set);
1065
- sigaddset(&set, SIGABRT);
1066
- pthread_sigmask(SIG_UNBLOCK, &set, NULL);
1067
- raise(SIGABRT);
1068
- usleep(1000);
1069
- __builtin_trap();
1070
- }
1071
- #endif /* __APPLE__ */
1072
-
1073
- void
1074
- installAgentAbortHandler() {
1075
- alternativeStackSize = MINSIGSTKSZ + 128 * 1024;
1076
- alternativeStack = (char *) malloc(alternativeStackSize);
1077
- if (alternativeStack == NULL) {
1078
- fprintf(stderr, "Cannot allocate an alternative with a size of %u bytes!\n",
1079
- alternativeStackSize);
1080
- fflush(stderr);
1081
- abort();
1082
- }
1083
-
1084
- stack_t stack;
1085
- stack.ss_sp = alternativeStack;
1086
- stack.ss_size = alternativeStackSize;
1087
- stack.ss_flags = 0;
1088
- if (sigaltstack(&stack, NULL) != 0) {
1089
- int e = errno;
1090
- fprintf(stderr, "Cannot install an alternative stack for use in signal handlers: %s (%d)\n",
1091
- strerror(e), e);
1092
- fflush(stderr);
1093
- abort();
1094
- }
1095
-
1096
- struct sigaction action;
1097
- action.sa_sigaction = abortHandler;
1098
- action.sa_flags = SA_RESETHAND | SA_SIGINFO;
1099
- sigemptyset(&action.sa_mask);
1100
- sigaction(SIGABRT, &action, NULL);
1101
- sigaction(SIGSEGV, &action, NULL);
1102
- sigaction(SIGBUS, &action, NULL);
1103
- sigaction(SIGFPE, &action, NULL);
1104
- sigaction(SIGILL, &action, NULL);
1105
- }
1106
-
1107
- void
1108
- installDiagnosticsDumper(DiagnosticsDumper func, void *userData) {
1109
- customDiagnosticsDumper = func;
1110
- customDiagnosticsDumperUserData = userData;
1111
- }
1112
-
1113
- bool
1114
- feedbackFdAvailable() {
1115
- return _feedbackFdAvailable;
1116
- }
1117
-
1118
- static int
1119
- lookupErrno(const char *name) {
1120
- struct Entry {
1121
- int errorCode;
1122
- const char * const name;
1123
- };
1124
- static const Entry entries[] = {
1125
- { EPERM, "EPERM" },
1126
- { ENOENT, "ENOENT" },
1127
- { ESRCH, "ESRCH" },
1128
- { EINTR, "EINTR" },
1129
- { EBADF, "EBADF" },
1130
- { ENOMEM, "ENOMEM" },
1131
- { EACCES, "EACCES" },
1132
- { EBUSY, "EBUSY" },
1133
- { EEXIST, "EEXIST" },
1134
- { ENOTDIR, "ENOTDIR" },
1135
- { EISDIR, "EISDIR" },
1136
- { EINVAL, "EINVAL" },
1137
- { ENFILE, "ENFILE" },
1138
- { EMFILE, "EMFILE" },
1139
- { ENOTTY, "ENOTTY" },
1140
- { ETXTBSY, "ETXTBSY" },
1141
- { ENOSPC, "ENOSPC" },
1142
- { ESPIPE, "ESPIPE" },
1143
- { EMLINK, "EMLINK" },
1144
- { EPIPE, "EPIPE" },
1145
- { EAGAIN, "EAGAIN" },
1146
- { EWOULDBLOCK, "EWOULDBLOCK" },
1147
- { EINPROGRESS, "EINPROGRESS" },
1148
- { EADDRINUSE, "EADDRINUSE" },
1149
- { EADDRNOTAVAIL, "EADDRNOTAVAIL" },
1150
- { ENETUNREACH, "ENETUNREACH" },
1151
- { ECONNABORTED, "ECONNABORTED" },
1152
- { ECONNRESET, "ECONNRESET" },
1153
- { EISCONN, "EISCONN" },
1154
- { ENOTCONN, "ENOTCONN" },
1155
- { ETIMEDOUT, "ETIMEDOUT" },
1156
- { ECONNREFUSED, "ECONNREFUSED" },
1157
- { EHOSTDOWN, "EHOSTDOWN" },
1158
- { EHOSTUNREACH, "EHOSTUNREACH" },
1159
- #ifdef EIO
1160
- { EIO, "EIO" },
1161
- #endif
1162
- #ifdef ENXIO
1163
- { ENXIO, "ENXIO" },
1164
- #endif
1165
- #ifdef E2BIG
1166
- { E2BIG, "E2BIG" },
1167
- #endif
1168
- #ifdef ENOEXEC
1169
- { ENOEXEC, "ENOEXEC" },
1170
- #endif
1171
- #ifdef ECHILD
1172
- { ECHILD, "ECHILD" },
1173
- #endif
1174
- #ifdef EDEADLK
1175
- { EDEADLK, "EDEADLK" },
1176
- #endif
1177
- #ifdef EFAULT
1178
- { EFAULT, "EFAULT" },
1179
- #endif
1180
- #ifdef ENOTBLK
1181
- { ENOTBLK, "ENOTBLK" },
1182
- #endif
1183
- #ifdef EXDEV
1184
- { EXDEV, "EXDEV" },
1185
- #endif
1186
- #ifdef ENODEV
1187
- { ENODEV, "ENODEV" },
1188
- #endif
1189
- #ifdef EFBIG
1190
- { EFBIG, "EFBIG" },
1191
- #endif
1192
- #ifdef EROFS
1193
- { EROFS, "EROFS" },
1194
- #endif
1195
- #ifdef EDOM
1196
- { EDOM, "EDOM" },
1197
- #endif
1198
- #ifdef ERANGE
1199
- { ERANGE, "ERANGE" },
1200
- #endif
1201
- #ifdef EALREADY
1202
- { EALREADY, "EALREADY" },
1203
- #endif
1204
- #ifdef ENOTSOCK
1205
- { ENOTSOCK, "ENOTSOCK" },
1206
- #endif
1207
- #ifdef EDESTADDRREQ
1208
- { EDESTADDRREQ, "EDESTADDRREQ" },
1209
- #endif
1210
- #ifdef EMSGSIZE
1211
- { EMSGSIZE, "EMSGSIZE" },
1212
- #endif
1213
- #ifdef EPROTOTYPE
1214
- { EPROTOTYPE, "EPROTOTYPE" },
1215
- #endif
1216
- #ifdef ENOPROTOOPT
1217
- { ENOPROTOOPT, "ENOPROTOOPT" },
1218
- #endif
1219
- #ifdef EPROTONOSUPPORT
1220
- { EPROTONOSUPPORT, "EPROTONOSUPPORT" },
1221
- #endif
1222
- #ifdef ESOCKTNOSUPPORT
1223
- { ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT" },
1224
- #endif
1225
- #ifdef ENOTSUP
1226
- { ENOTSUP, "ENOTSUP" },
1227
- #endif
1228
- #ifdef EOPNOTSUPP
1229
- { EOPNOTSUPP, "EOPNOTSUPP" },
1230
- #endif
1231
- #ifdef EPFNOSUPPORT
1232
- { EPFNOSUPPORT, "EPFNOSUPPORT" },
1233
- #endif
1234
- #ifdef EAFNOSUPPORT
1235
- { EAFNOSUPPORT, "EAFNOSUPPORT" },
1236
- #endif
1237
- #ifdef ENETDOWN
1238
- { ENETDOWN, "ENETDOWN" },
1239
- #endif
1240
- #ifdef ENETRESET
1241
- { ENETRESET, "ENETRESET" },
1242
- #endif
1243
- #ifdef ENOBUFS
1244
- { ENOBUFS, "ENOBUFS" },
1245
- #endif
1246
- #ifdef ESHUTDOWN
1247
- { ESHUTDOWN, "ESHUTDOWN" },
1248
- #endif
1249
- #ifdef ETOOMANYREFS
1250
- { ETOOMANYREFS, "ETOOMANYREFS" },
1251
- #endif
1252
- #ifdef ELOOP
1253
- { ELOOP, "ELOOP" },
1254
- #endif
1255
- #ifdef ENAMETOOLONG
1256
- { ENAMETOOLONG, "ENAMETOOLONG" },
1257
- #endif
1258
- #ifdef ENOTEMPTY
1259
- { ENOTEMPTY, "ENOTEMPTY" },
1260
- #endif
1261
- #ifdef EPROCLIM
1262
- { EPROCLIM, "EPROCLIM" },
1263
- #endif
1264
- #ifdef EUSERS
1265
- { EUSERS, "EUSERS" },
1266
- #endif
1267
- #ifdef EDQUOT
1268
- { EDQUOT, "EDQUOT" },
1269
- #endif
1270
- #ifdef ESTALE
1271
- { ESTALE, "ESTALE" },
1272
- #endif
1273
- #ifdef EREMOTE
1274
- { EREMOTE, "EREMOTE" },
1275
- #endif
1276
- #ifdef EBADRPC
1277
- { EBADRPC, "EBADRPC" },
1278
- #endif
1279
- #ifdef ERPCMISMATCH
1280
- { ERPCMISMATCH, "ERPCMISMATCH" },
1281
- #endif
1282
- #ifdef EPROGUNAVAIL
1283
- { EPROGUNAVAIL, "EPROGUNAVAIL" },
1284
- #endif
1285
- #ifdef EPROGMISMATCH
1286
- { EPROGMISMATCH, "EPROGMISMATCH" },
1287
- #endif
1288
- #ifdef EPROCUNAVAIL
1289
- { EPROCUNAVAIL, "EPROCUNAVAIL" },
1290
- #endif
1291
- #ifdef ENOLCK
1292
- { ENOLCK, "ENOLCK" },
1293
- #endif
1294
- #ifdef ENOSYS
1295
- { ENOSYS, "ENOSYS" },
1296
- #endif
1297
- #ifdef EFTYPE
1298
- { EFTYPE, "EFTYPE" },
1299
- #endif
1300
- #ifdef EAUTH
1301
- { EAUTH, "EAUTH" },
1302
- #endif
1303
- #ifdef ENEEDAUTH
1304
- { ENEEDAUTH, "ENEEDAUTH" },
1305
- #endif
1306
- #ifdef EPWROFF
1307
- { EPWROFF, "EPWROFF" },
1308
- #endif
1309
- #ifdef EDEVERR
1310
- { EDEVERR, "EDEVERR" },
1311
- #endif
1312
- #ifdef EOVERFLOW
1313
- { EOVERFLOW, "EOVERFLOW" },
1314
- #endif
1315
- #ifdef EBADEXEC
1316
- { EBADEXEC, "EBADEXEC" },
1317
- #endif
1318
- #ifdef EBADARCH
1319
- { EBADARCH, "EBADARCH" },
1320
- #endif
1321
- #ifdef ESHLIBVERS
1322
- { ESHLIBVERS, "ESHLIBVERS" },
1323
- #endif
1324
- #ifdef EBADMACHO
1325
- { EBADMACHO, "EBADMACHO" },
1326
- #endif
1327
- #ifdef ECANCELED
1328
- { ECANCELED, "ECANCELED" },
1329
- #endif
1330
- #ifdef EIDRM
1331
- { EIDRM, "EIDRM" },
1332
- #endif
1333
- #ifdef ENOMSG
1334
- { ENOMSG, "ENOMSG" },
1335
- #endif
1336
- #ifdef EILSEQ
1337
- { EILSEQ, "EILSEQ" },
1338
- #endif
1339
- #ifdef ENOATTR
1340
- { ENOATTR, "ENOATTR" },
1341
- #endif
1342
- #ifdef EBADMSG
1343
- { EBADMSG, "EBADMSG" },
1344
- #endif
1345
- #ifdef EMULTIHOP
1346
- { EMULTIHOP, "EMULTIHOP" },
1347
- #endif
1348
- #ifdef ENODATA
1349
- { ENODATA, "ENODATA" },
1350
- #endif
1351
- #ifdef ENOLINK
1352
- { ENOLINK, "ENOLINK" },
1353
- #endif
1354
- #ifdef ENOSR
1355
- { ENOSR, "ENOSR" },
1356
- #endif
1357
- #ifdef ENOSTR
1358
- { ENOSTR, "ENOSTR" },
1359
- #endif
1360
- #ifdef EPROTO
1361
- { EPROTO, "EPROTO" },
1362
- #endif
1363
- #ifdef ETIME
1364
- { ETIME, "ETIME" },
1365
- #endif
1366
- #ifdef EOPNOTSUPP
1367
- { EOPNOTSUPP, "EOPNOTSUPP" },
1368
- #endif
1369
- #ifdef ENOPOLICY
1370
- { ENOPOLICY, "ENOPOLICY" },
1371
- #endif
1372
- #ifdef ENOTRECOVERABLE
1373
- { ENOTRECOVERABLE, "ENOTRECOVERABLE" },
1374
- #endif
1375
- #ifdef EOWNERDEAD
1376
- { EOWNERDEAD, "EOWNERDEAD" },
1377
- #endif
1378
- };
1379
-
1380
- for (unsigned int i = 0; i < sizeof(entries) / sizeof(Entry); i++) {
1381
- if (strcmp(entries[i].name, name) == 0) {
1382
- return entries[i].errorCode;
1383
- }
1384
- }
1385
- return -1;
1386
- }
1387
-
1388
- static void
1389
- initializeSyscallFailureSimulation(const char *processName) {
1390
- // Format:
1391
- // PassengerAgent watchdog=EMFILE:0.1,ECONNREFUSED:0.25;PassengerAgent core=ESPIPE=0.4
1392
- const char *spec = getenv("PASSENGER_SIMULATE_SYSCALL_FAILURES");
1393
- string prefix = string(processName) + "=";
1394
- vector<string> components;
1395
- unsigned int i;
1396
-
1397
- // Lookup this process in the specification string.
1398
- split(spec, ';', components);
1399
- for (i = 0; i < components.size(); i++) {
1400
- if (startsWith(components[i], prefix)) {
1401
- // Found!
1402
- string value = components[i].substr(prefix.size());
1403
- split(value, ',', components);
1404
- vector<string> keyAndValue;
1405
- vector<ErrorChance> chances;
1406
-
1407
- // Process each errorCode:chance pair.
1408
- for (i = 0; i < components.size(); i++) {
1409
- split(components[i], ':', keyAndValue);
1410
- if (keyAndValue.size() != 2) {
1411
- fprintf(stderr, "%s: invalid syntax in PASSENGER_SIMULATE_SYSCALL_FAILURES: '%s'\n",
1412
- processName, components[i].c_str());
1413
- continue;
1414
- }
1415
-
1416
- int e = lookupErrno(keyAndValue[0].c_str());
1417
- if (e == -1) {
1418
- fprintf(stderr, "%s: invalid error code in PASSENGER_SIMULATE_SYSCALL_FAILURES: '%s'\n",
1419
- processName, components[i].c_str());
1420
- continue;
1421
- }
1422
-
1423
- ErrorChance chance;
1424
- chance.chance = atof(keyAndValue[1].c_str());
1425
- if (chance.chance < 0 || chance.chance > 1) {
1426
- fprintf(stderr, "%s: invalid chance PASSENGER_SIMULATE_SYSCALL_FAILURES: '%s' - chance must be between 0 and 1\n",
1427
- processName, components[i].c_str());
1428
- continue;
1429
- }
1430
- chance.errorCode = e;
1431
- chances.push_back(chance);
1432
- }
1433
-
1434
- // Install the chances.
1435
- setup_random_failure_simulation(&chances[0], chances.size());
1436
- return;
1437
- }
1438
- }
1439
- }
1440
-
1441
- static bool isBlank(const char *str) {
1442
- while (*str != '\0') {
1443
- if (*str != ' ') {
1444
- return false;
1445
- }
1446
- str++;
1447
- }
1448
- return true;
1449
- }
1450
-
1451
- static bool
1452
- extraArgumentsPassed(int argc, char *argv[], int argStartIndex) {
1453
- assert(argc >= argStartIndex);
1454
- return argc > argStartIndex + 1
1455
- // Allow the Watchdog to pass an all-whitespace argument. This
1456
- // argument provides the memory space for us to change the process title.
1457
- || (argc == argStartIndex + 1 && !isBlank(argv[argStartIndex]));
1458
- }
1459
-
1460
- static void
1461
- initializeLoggingKit(const char *processName, VariantMap &options) {
1462
- Json::Value config(Json::objectValue);
1463
-
1464
- options.setDefaultInt("log_level", DEFAULT_LOG_LEVEL);
1465
- config["level"] = options.get("log_level");
1466
-
1467
- if (options.has("log_file")) {
1468
- config["target"] = options.get("log_file");
1469
- } else if (options.has("debug_log_file")) {
1470
- config["target"] = options.get("debug_log_file");
1471
- }
1472
-
1473
- if (options.has("file_descriptor_log_file")) {
1474
- config["file_descriptor_log_target"] =
1475
- options.get("file_descriptor_log_file");
1476
- }
1477
-
1478
- LoggingKit::initialize(config);
1479
-
1480
- if (options.has("file_descriptor_log_file")) {
1481
- // This information helps ./dev/parse_file_descriptor_log.
1482
- FastStringStream<> stream;
1483
- LoggingKit::_prepareLogEntry(stream, LoggingKit::CRIT, __FILE__, __LINE__);
1484
- stream << "Starting agent: " << processName << "\n";
1485
- _writeFileDescriptorLogEntry(LoggingKit::context->getConfigRealization(),
1486
- stream.data(), stream.size());
1487
-
1488
- config = LoggingKit::context->getConfig().inspect();
1489
- P_LOG_FILE_DESCRIPTOR_OPEN4(
1490
- LoggingKit::context->getConfigRealization()->fileDescriptorLogTargetFd,
1491
- __FILE__, __LINE__,
1492
- "file descriptor log file "
1493
- << config["file_descriptor_log_target"]["effective_value"]["path"].asString());
1494
- } else {
1495
- // This information helps ./dev/parse_file_descriptor_log.
1496
- P_DEBUG("Starting agent: " << processName);
1497
- }
1498
- }
1499
-
1500
- VariantMap
1501
- initializeAgent(int argc, char **argv[], const char *processName,
1502
- OptionParserFunc optionParser, PreinitializationFunc preinit,
1503
- int argStartIndex)
1504
- {
1505
- VariantMap options;
1506
- const char *seedStr;
1507
-
1508
- seedStr = getEnvString("PASSENGER_RANDOM_SEED");
1509
- if (seedStr == NULL) {
1510
- randomSeed = (unsigned int) time(NULL);
1511
- } else {
1512
- randomSeed = (unsigned int) atoll(seedStr);
1513
- }
1514
- srand(randomSeed);
1515
- srandom(randomSeed);
1516
-
1517
- ignoreSigpipe();
1518
- if (hasEnvOption("PASSENGER_ABORT_HANDLER", true)) {
1519
- shouldDumpWithCrashWatch = hasEnvOption("PASSENGER_DUMP_WITH_CRASH_WATCH", true);
1520
- beepOnAbort = hasEnvOption("PASSENGER_BEEP_ON_ABORT");
1521
- stopOnAbort = hasEnvOption("PASSENGER_STOP_ON_ABORT");
1522
- IGNORE_SYSCALL_RESULT(pipe(emergencyPipe1));
1523
- IGNORE_SYSCALL_RESULT(pipe(emergencyPipe2));
1524
- installAgentAbortHandler();
1525
- }
1526
- oxt::initialize();
1527
- setup_syscall_interruption_support();
1528
- if (hasEnvOption("PASSENGER_SIMULATE_SYSCALL_FAILURES")) {
1529
- initializeSyscallFailureSimulation(processName);
1530
- }
1531
- SystemTime::initialize();
1532
- setvbuf(stdout, NULL, _IONBF, 0);
1533
- setvbuf(stderr, NULL, _IONBF, 0);
1534
-
1535
- TRACE_POINT();
1536
- try {
1537
- if (hasEnvOption("PASSENGER_USE_FEEDBACK_FD")) {
1538
- if (extraArgumentsPassed(argc, *argv, argStartIndex)) {
1539
- fprintf(stderr, "No arguments may be passed when using the feedback FD.\n");
1540
- exit(1);
1541
- }
1542
- _feedbackFdAvailable = true;
1543
- options.readFrom(FEEDBACK_FD);
1544
- } else if (optionParser != NULL) {
1545
- optionParser(argc, (const char **) *argv, options);
1546
- } else {
1547
- options.readFrom((const char **) *argv + argStartIndex,
1548
- argc - argStartIndex);
1549
- }
1550
-
1551
- initializeAgentOptions(processName, options, preinit);
1552
- } catch (const tracable_exception &e) {
1553
- P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace());
1554
- exit(1);
1555
- }
1556
-
1557
- storeArgvCopy(argc, *argv);
1558
-
1559
- // Change process title.
1560
- size_t totalArgLen = strlen((*argv)[0]);
1561
- for (int i = 1; i < argc; i++) {
1562
- size_t len = strlen((*argv)[i]);
1563
- totalArgLen += len + 1;
1564
- memset((*argv)[i], '\0', len);
1565
- }
1566
- strncpy((*argv)[0], processName, totalArgLen);
1567
- *argv = origArgv;
1568
-
1569
- P_DEBUG("Random seed: " << randomSeed);
1570
-
1571
- return options;
1572
- }
1573
-
1574
- void
1575
- initializeAgentOptions(const char *processName, VariantMap &options,
1576
- PreinitializationFunc preinit)
1577
- {
1578
- ResourceLocator locator;
1579
- string ruby;
1580
-
1581
- if (options.has("passenger_root")) {
1582
- string path;
1583
- locator = ResourceLocator(options.get("passenger_root", true));
1584
- ruby = options.get("default_ruby", false, DEFAULT_RUBY);
1585
-
1586
- rubyLibDir = strdup(locator.getRubyLibDir().c_str());
1587
- passengerRoot = strdup(options.get("passenger_root", true).c_str());
1588
- defaultRuby = strdup(ruby.c_str());
1589
-
1590
- #ifdef __linux__
1591
- path = ruby + " \"" + locator.getHelperScriptsDir() +
1592
- "/backtrace-sanitizer.rb\"";
1593
- backtraceSanitizerCommand = strdup(path.c_str());
1594
- #endif
1595
-
1596
- path = locator.getHelperScriptsDir() + "/crash-watch.rb";
1597
- crashWatch = strdup(path.c_str());
1598
- } else {
1599
- shouldDumpWithCrashWatch = false;
1600
- }
1601
-
1602
- if (backtraceSanitizerCommand == NULL) {
1603
- backtraceSanitizerCommand = "c++filt -n";
1604
- backtraceSanitizerPassProgramInfo = false;
1605
- }
1606
-
1607
- if (preinit != NULL) {
1608
- preinit(options);
1609
- }
1610
-
1611
- initializeLoggingKit(processName, options);
1612
-
1613
- if (hasEnvOption("PASSENGER_USE_FEEDBACK_FD")) {
1614
- P_LOG_FILE_DESCRIPTOR_OPEN2(FEEDBACK_FD, "feedback FD");
1615
- }
1616
- if (emergencyPipe1[0] != -1) {
1617
- P_LOG_FILE_DESCRIPTOR_OPEN4(emergencyPipe1[0], __FILE__, __LINE__,
1618
- "Emergency pipe 1-0");
1619
- P_LOG_FILE_DESCRIPTOR_OPEN4(emergencyPipe1[1], __FILE__, __LINE__,
1620
- "Emergency pipe 1-1");
1621
- P_LOG_FILE_DESCRIPTOR_OPEN4(emergencyPipe2[0], __FILE__, __LINE__,
1622
- "Emergency pipe 2-0");
1623
- P_LOG_FILE_DESCRIPTOR_OPEN4(emergencyPipe2[1], __FILE__, __LINE__,
1624
- "Emergency pipe 2-1");
1625
- }
1626
- }
1627
-
1628
- void
1629
- storeArgvCopy(int argc, char *argv[]) {
1630
- // Make a copy of the arguments before changing process title.
1631
- origArgv = (char **) malloc(argc * sizeof(char *));
1632
- for (int i = 0; i < argc; i++) {
1633
- origArgv[i] = strdup(argv[i]);
1634
- }
1635
- }
1636
-
1637
- void
1638
- shutdownAgent(VariantMap *agentOptions) {
1639
- delete agentOptions;
1640
- oxt::shutdown();
1641
- }
1642
-
1643
- /**
1644
- * Linux-only way to change OOM killer configuration for
1645
- * current process. Requires root privileges, which we
1646
- * should have.
1647
- */
1648
- void
1649
- restoreOomScore(VariantMap *agentOptions) {
1650
- TRACE_POINT();
1651
-
1652
- string score = agentOptions->get("original_oom_score", false);
1653
- if (score.empty()) {
1654
- return;
1655
- }
1656
-
1657
- FILE *f;
1658
- bool legacy = false;
1659
-
1660
- if (score.at(0) == 'l') {
1661
- legacy = true;
1662
- score = score.substr(1);
1663
- f = fopen("/proc/self/oom_adj", "w");
1664
- } else {
1665
- f = fopen("/proc/self/oom_score_adj", "w");
1666
- }
1667
-
1668
- if (f != NULL) {
1669
- fprintf(f, "%s\n", score.c_str());
1670
- fclose(f);
1671
- } else {
1672
- P_WARN("Unable to set OOM score to " << score << " (legacy: " << legacy
1673
- << ") due to error: " << strerror(errno)
1674
- << " (process will remain at inherited OOM score)");
1675
- }
1676
- }
1677
-
1678
- } // namespace Passenger