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
@@ -0,0 +1,459 @@
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
+
27
+ #ifndef _GNU_SOURCE
28
+ #define _GNU_SOURCE // according to Linux man page for syscall()
29
+ #endif
30
+
31
+ #include <sys/types.h>
32
+ #include <sys/resource.h>
33
+ #include <sys/stat.h>
34
+ #include <sys/wait.h>
35
+ #include <unistd.h>
36
+ #include <signal.h>
37
+ #include <fcntl.h>
38
+ #include <stdlib.h>
39
+ #include <dirent.h>
40
+ #include <poll.h>
41
+ #ifdef __linux__
42
+ #include <sys/syscall.h>
43
+ #include <features.h>
44
+ #endif
45
+
46
+ #include <string>
47
+ #include <cstddef>
48
+ #include <cstring>
49
+ #include <climits>
50
+ #include <cerrno>
51
+
52
+ #include <ProcessManagement/Utils.h>
53
+ #include <Utils/AsyncSignalSafeUtils.h>
54
+
55
+ #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
56
+ // Introduced in Solaris 9. Let's hope nobody actually uses
57
+ // a version that doesn't support this.
58
+ #define HAS_CLOSEFROM
59
+ #endif
60
+
61
+ namespace Passenger {
62
+
63
+ using namespace std;
64
+
65
+
66
+ #ifdef __APPLE__
67
+ // http://www.opensource.apple.com/source/Libc/Libc-825.26/sys/fork.c
68
+ // This bypasses atfork handlers.
69
+ extern "C" {
70
+ extern pid_t __fork(void);
71
+ }
72
+ #endif
73
+
74
+ pid_t
75
+ asyncFork() {
76
+ #if defined(__linux__)
77
+ #if defined(SYS_fork)
78
+ return (pid_t) syscall(SYS_fork);
79
+ #else
80
+ return syscall(SYS_clone, SIGCHLD, 0, 0, 0, 0);
81
+ #endif
82
+ #elif defined(__APPLE__)
83
+ return __fork();
84
+ #else
85
+ return fork();
86
+ #endif
87
+ }
88
+
89
+ void
90
+ resetSignalHandlersAndMask() {
91
+ struct sigaction action;
92
+ action.sa_handler = SIG_DFL;
93
+ action.sa_flags = SA_RESTART;
94
+ sigemptyset(&action.sa_mask);
95
+ sigaction(SIGHUP, &action, NULL);
96
+ sigaction(SIGINT, &action, NULL);
97
+ sigaction(SIGQUIT, &action, NULL);
98
+ sigaction(SIGILL, &action, NULL);
99
+ sigaction(SIGTRAP, &action, NULL);
100
+ sigaction(SIGABRT, &action, NULL);
101
+ #ifdef SIGEMT
102
+ sigaction(SIGEMT, &action, NULL);
103
+ #endif
104
+ sigaction(SIGFPE, &action, NULL);
105
+ sigaction(SIGBUS, &action, NULL);
106
+ sigaction(SIGSEGV, &action, NULL);
107
+ sigaction(SIGSYS, &action, NULL);
108
+ sigaction(SIGPIPE, &action, NULL);
109
+ sigaction(SIGALRM, &action, NULL);
110
+ sigaction(SIGTERM, &action, NULL);
111
+ sigaction(SIGURG, &action, NULL);
112
+ sigaction(SIGSTOP, &action, NULL);
113
+ sigaction(SIGTSTP, &action, NULL);
114
+ sigaction(SIGCONT, &action, NULL);
115
+ sigaction(SIGCHLD, &action, NULL);
116
+ #ifdef SIGINFO
117
+ sigaction(SIGINFO, &action, NULL);
118
+ #endif
119
+ sigaction(SIGUSR1, &action, NULL);
120
+ sigaction(SIGUSR2, &action, NULL);
121
+
122
+ // We reset the signal mask after resetting the signal handlers,
123
+ // because prior to calling resetSignalHandlersAndMask(), the
124
+ // process might be blocked on some signals. We want those signals
125
+ // to be processed after installing the new signal handlers
126
+ // so that bugs like https://github.com/phusion/passenger/pull/97
127
+ // can be prevented.
128
+
129
+ sigset_t signal_set;
130
+ int ret;
131
+
132
+ sigemptyset(&signal_set);
133
+ do {
134
+ ret = sigprocmask(SIG_SETMASK, &signal_set, NULL);
135
+ } while (ret == -1 && errno == EINTR);
136
+ }
137
+
138
+ void
139
+ disableMallocDebugging() {
140
+ unsetenv("MALLOC_FILL_SPACE");
141
+ unsetenv("MALLOC_PROTECT_BEFORE");
142
+ unsetenv("MallocGuardEdges");
143
+ unsetenv("MallocScribble");
144
+ unsetenv("MallocPreScribble");
145
+ unsetenv("MallocCheckHeapStart");
146
+ unsetenv("MallocCheckHeapEach");
147
+ unsetenv("MallocCheckHeapAbort");
148
+ unsetenv("MallocBadFreeAbort");
149
+ unsetenv("MALLOC_CHECK_");
150
+
151
+ const char *libs = getenv("DYLD_INSERT_LIBRARIES");
152
+ if (libs != NULL && strstr(libs, "/usr/lib/libgmalloc.dylib")) {
153
+ string newLibs = libs;
154
+ string::size_type pos = newLibs.find("/usr/lib/libgmalloc.dylib");
155
+ size_t len = strlen("/usr/lib/libgmalloc.dylib");
156
+
157
+ // Erase all leading ':' too.
158
+ while (pos > 0 && newLibs[pos - 1] == ':') {
159
+ pos--;
160
+ len++;
161
+ }
162
+ // Erase all trailing ':' too.
163
+ while (pos + len < newLibs.size() && newLibs[pos + len] == ':') {
164
+ len++;
165
+ }
166
+
167
+ newLibs.erase(pos, len);
168
+ if (newLibs.empty()) {
169
+ unsetenv("DYLD_INSERT_LIBRARIES");
170
+ } else {
171
+ setenv("DYLD_INSERT_LIBRARIES", newLibs.c_str(), 1);
172
+ }
173
+ }
174
+ }
175
+
176
+ // Async-signal safe way to get the current process's hard file descriptor limit.
177
+ static int
178
+ getFileDescriptorLimit() {
179
+ long long sysconfResult = sysconf(_SC_OPEN_MAX);
180
+
181
+ struct rlimit rl;
182
+ long long rlimitResult;
183
+ if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
184
+ rlimitResult = 0;
185
+ } else {
186
+ rlimitResult = (long long) rl.rlim_max;
187
+ }
188
+
189
+ long result;
190
+ // OS X 10.9 returns LLONG_MAX. It doesn't make sense
191
+ // to use that result so we limit ourselves to the
192
+ // sysconf result.
193
+ if (rlimitResult >= INT_MAX || sysconfResult > rlimitResult) {
194
+ result = sysconfResult;
195
+ } else {
196
+ result = rlimitResult;
197
+ }
198
+
199
+ if (result < 0) {
200
+ // Unable to query the file descriptor limit.
201
+ result = 9999;
202
+ } else if (result < 2) {
203
+ // The calls reported broken values.
204
+ result = 2;
205
+ }
206
+ return result;
207
+ }
208
+
209
+ // Async-signal safe function to get the highest file
210
+ // descriptor that the process is currently using.
211
+ // See also http://stackoverflow.com/questions/899038/getting-the-highest-allocated-file-descriptor
212
+ static int
213
+ getHighestFileDescriptor(bool asyncSignalSafe) {
214
+ #if defined(F_MAXFD)
215
+ int ret;
216
+
217
+ do {
218
+ ret = fcntl(0, F_MAXFD);
219
+ } while (ret == -1 && errno == EINTR);
220
+ if (ret == -1) {
221
+ ret = getFileDescriptorLimit();
222
+ }
223
+ return ret;
224
+
225
+ #else
226
+ int p[2], ret, flags;
227
+ pid_t pid = -1;
228
+ int result = -1;
229
+
230
+ /* Since opendir() may not be async signal safe and thus may lock up
231
+ * or crash, we use it in a child process which we kill if we notice
232
+ * that things are going wrong.
233
+ */
234
+
235
+ // Make a pipe.
236
+ p[0] = p[1] = -1;
237
+ do {
238
+ ret = pipe(p);
239
+ } while (ret == -1 && errno == EINTR);
240
+ if (ret == -1) {
241
+ goto done;
242
+ }
243
+
244
+ // Make the read side non-blocking.
245
+ do {
246
+ flags = fcntl(p[0], F_GETFL);
247
+ } while (flags == -1 && errno == EINTR);
248
+ if (flags == -1) {
249
+ goto done;
250
+ }
251
+ do {
252
+ fcntl(p[0], F_SETFL, flags | O_NONBLOCK);
253
+ } while (ret == -1 && errno == EINTR);
254
+ if (ret == -1) {
255
+ goto done;
256
+ }
257
+
258
+ if (asyncSignalSafe) {
259
+ do {
260
+ pid = asyncFork();
261
+ } while (pid == -1 && errno == EINTR);
262
+ } else {
263
+ do {
264
+ pid = fork();
265
+ } while (pid == -1 && errno == EINTR);
266
+ }
267
+
268
+ if (pid == 0) {
269
+ // Don't close p[0] here or it might affect the result.
270
+
271
+ resetSignalHandlersAndMask();
272
+
273
+ struct sigaction action;
274
+ action.sa_handler = _exit;
275
+ action.sa_flags = SA_RESTART;
276
+ sigemptyset(&action.sa_mask);
277
+ sigaction(SIGSEGV, &action, NULL);
278
+ sigaction(SIGPIPE, &action, NULL);
279
+ sigaction(SIGBUS, &action, NULL);
280
+ sigaction(SIGILL, &action, NULL);
281
+ sigaction(SIGFPE, &action, NULL);
282
+ sigaction(SIGABRT, &action, NULL);
283
+
284
+ DIR *dir = NULL;
285
+ #ifdef __APPLE__
286
+ /* /dev/fd can always be trusted on OS X. */
287
+ dir = opendir("/dev/fd");
288
+ #else
289
+ /* On FreeBSD and possibly other operating systems, /dev/fd only
290
+ * works if fdescfs is mounted. If it isn't mounted then /dev/fd
291
+ * still exists but always returns [0, 1, 2] and thus can't be
292
+ * trusted. If /dev and /dev/fd are on different filesystems
293
+ * then that probably means fdescfs is mounted.
294
+ */
295
+ struct stat dirbuf1, dirbuf2;
296
+ if (stat("/dev", &dirbuf1) == -1
297
+ || stat("/dev/fd", &dirbuf2) == -1) {
298
+ _exit(1);
299
+ }
300
+ if (dirbuf1.st_dev != dirbuf2.st_dev) {
301
+ dir = opendir("/dev/fd");
302
+ }
303
+ #endif
304
+ if (dir == NULL) {
305
+ dir = opendir("/proc/self/fd");
306
+ if (dir == NULL) {
307
+ _exit(1);
308
+ }
309
+ }
310
+
311
+ struct dirent *ent;
312
+ union {
313
+ int highest;
314
+ char data[sizeof(int)];
315
+ } u;
316
+ u.highest = -1;
317
+
318
+ while ((ent = readdir(dir)) != NULL) {
319
+ if (ent->d_name[0] != '.') {
320
+ int number = atoi(ent->d_name);
321
+ if (number > u.highest) {
322
+ u.highest = number;
323
+ }
324
+ }
325
+ }
326
+ if (u.highest != -1) {
327
+ ssize_t ret, written = 0;
328
+ do {
329
+ ret = write(p[1], u.data + written, sizeof(int) - written);
330
+ if (ret == -1) {
331
+ _exit(1);
332
+ }
333
+ written += ret;
334
+ } while (written < (ssize_t) sizeof(int));
335
+ }
336
+ closedir(dir);
337
+ _exit(0);
338
+
339
+ } else if (pid == -1) {
340
+ goto done;
341
+
342
+ } else {
343
+ close(p[1]); // Do not retry on EINTR: http://news.ycombinator.com/item?id=3363819
344
+ p[1] = -1;
345
+
346
+ union {
347
+ int highest;
348
+ char data[sizeof(int)];
349
+ } u;
350
+ ssize_t ret, bytesRead = 0;
351
+ struct pollfd pfd;
352
+ pfd.fd = p[0];
353
+ pfd.events = POLLIN;
354
+
355
+ do {
356
+ do {
357
+ // The child process must finish within 30 ms, otherwise
358
+ // we might as well query sysconf.
359
+ ret = poll(&pfd, 1, 30);
360
+ } while (ret == -1 && errno == EINTR);
361
+ if (ret <= 0) {
362
+ goto done;
363
+ }
364
+
365
+ do {
366
+ ret = read(p[0], u.data + bytesRead, sizeof(int) - bytesRead);
367
+ } while (ret == -1 && errno == EINTR);
368
+ if (ret == -1) {
369
+ if (errno != EAGAIN) {
370
+ goto done;
371
+ }
372
+ } else if (ret == 0) {
373
+ goto done;
374
+ } else {
375
+ bytesRead += ret;
376
+ }
377
+ } while (bytesRead < (ssize_t) sizeof(int));
378
+
379
+ result = u.highest;
380
+ goto done;
381
+ }
382
+
383
+ done:
384
+ // Do not retry on EINTR: http://news.ycombinator.com/item?id=3363819
385
+ if (p[0] != -1) {
386
+ close(p[0]);
387
+ }
388
+ if (p[1] != -1) {
389
+ close(p[1]);
390
+ }
391
+ if (pid != -1) {
392
+ do {
393
+ ret = kill(pid, SIGKILL);
394
+ } while (ret == -1 && errno == EINTR);
395
+ do {
396
+ ret = waitpid(pid, NULL, 0);
397
+ } while (ret == -1 && errno == EINTR);
398
+ }
399
+
400
+ if (result == -1) {
401
+ result = getFileDescriptorLimit();
402
+ }
403
+ return result;
404
+ #endif
405
+ }
406
+
407
+ void
408
+ closeAllFileDescriptors(int lastToKeepOpen, bool asyncSignalSafe) {
409
+ #if defined(F_CLOSEM)
410
+ int ret;
411
+ do {
412
+ ret = fcntl(lastToKeepOpen + 1, F_CLOSEM);
413
+ } while (ret == -1 && errno == EINTR);
414
+ if (ret != -1) {
415
+ return;
416
+ }
417
+ #elif defined(HAS_CLOSEFROM)
418
+ closefrom(lastToKeepOpen + 1);
419
+ return;
420
+ #endif
421
+
422
+ for (int i = getHighestFileDescriptor(asyncSignalSafe); i > lastToKeepOpen; i--) {
423
+ /* Even though we normally shouldn't retry on EINTR
424
+ * (http://news.ycombinator.com/item?id=3363819)
425
+ * it's okay to do that here because because this function
426
+ * may only be called in a single-threaded environment.
427
+ */
428
+ int ret;
429
+ do {
430
+ ret = close(i);
431
+ } while (ret == -1 && errno == EINTR);
432
+ }
433
+ }
434
+
435
+ void
436
+ printExecError(const char **command, int errcode) {
437
+ char buf[1024];
438
+ printExecError2(command, errcode, buf, sizeof(buf));
439
+ }
440
+
441
+ void
442
+ printExecError2(const char **command, int errcode, char *buf, size_t size) {
443
+ char *pos = buf;
444
+ const char *end = buf + size;
445
+
446
+ pos = AsyncSignalSafeUtils::appendData(pos, end, "*** ERROR: cannot execute ");
447
+ pos = AsyncSignalSafeUtils::appendData(pos, end, command[0]);
448
+ pos = AsyncSignalSafeUtils::appendData(pos, end, ": ");
449
+ pos = AsyncSignalSafeUtils::appendData(pos, end,
450
+ AsyncSignalSafeUtils::limitedStrerror(errcode));
451
+ pos = AsyncSignalSafeUtils::appendData(pos, end, " (errno=");
452
+ pos = AsyncSignalSafeUtils::appendInteger<int, 10>(pos, end, errcode);
453
+ pos = AsyncSignalSafeUtils::appendData(pos, end, ")\n");
454
+
455
+ AsyncSignalSafeUtils::printError(buf, end - pos);
456
+ }
457
+
458
+
459
+ } // namespace Passenger