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,107 @@
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 _PASSENGER_PROCESS_MANAGEMENT_UTILS_H_
27
+ #define _PASSENGER_PROCESS_MANAGEMENT_UTILS_H_
28
+
29
+ #include <sys/types.h>
30
+
31
+ namespace Passenger {
32
+
33
+ using namespace std;
34
+
35
+
36
+ /**
37
+ * Thread-safe and async-signal safe way to fork().
38
+ *
39
+ * On Linux, the fork() glibc wrapper grabs a ptmalloc lock, so
40
+ * if malloc causes a segfault then we can't fork.
41
+ * http://sourceware.org/bugzilla/show_bug.cgi?id=4737
42
+ *
43
+ * OS X apparently does something similar, except they use a
44
+ * spinlock so it results in 100% CPU. See _cthread_fork_prepare()
45
+ * at http://www.opensource.apple.com/source/Libc/Libc-166/threads.subproj/cthreads.c
46
+ * However, since POSIX in OS X is implemented on top of a Mach layer,
47
+ * calling asyncFork() can mess up the state of the Mach layer, causing
48
+ * some POSIX functions to mysteriously fail. See
49
+ * https://code.google.com/p/phusion-passenger/issues/detail?id=1094
50
+ * You should therefore not use asyncFork() unless you're in a signal
51
+ * handler or if you only perform async-signal-safe stuff in the child.
52
+ *
53
+ * On 2017 October 9 with macOS 10.11 El Capitan, we also confirmed
54
+ * a case in which the child process can get stuck indefinitely with 0% CPU.
55
+ * If we we create a thread which performs memory allocation, and shortly
56
+ * after thread creation we fork, then the child process gets stuck because
57
+ * one of its pthread_atfork() handlers tries to allocate memory, which tries
58
+ * to grab a lock which was already locked. This means that on macOS
59
+ * we pretty much can never use regular fork() at all in a multithreaded
60
+ * environment.
61
+ */
62
+ pid_t asyncFork();
63
+
64
+ /**
65
+ * Resets the current process's signal handler disposition and signal mask
66
+ * to default values. One should call this every time one forks a child process;
67
+ * non-default signal masks/handler dispositions can cause all kinds of weird quirks,
68
+ * like waitpid() malfunctioning on macOS.
69
+ *
70
+ * This function is async-signal safe.
71
+ */
72
+ void resetSignalHandlersAndMask();
73
+
74
+ /**
75
+ * Disables malloc() debugging facilities on macOS.
76
+ */
77
+ void disableMallocDebugging();
78
+
79
+ /**
80
+ * Close all file descriptors that are higher than `lastToKeepOpen`.
81
+ *
82
+ * If you set `asyncSignalSafe` to true, then this function becomes fully async-signal,
83
+ * through the use of asyncFork() instead of fork(). However, read the documentation
84
+ * for asyncFork() to learn about its caveats.
85
+ *
86
+ * Also, regardless of whether `asyncSignalSafe` is true or not, this function is not
87
+ * *thread* safe. Make sure there are no other threads running that might open file
88
+ * descriptors, otherwise some file descriptors might not be closed even though they
89
+ * should be.
90
+ */
91
+ void closeAllFileDescriptors(int lastToKeepOpen, bool asyncSignalSafe = false);
92
+
93
+ /**
94
+ * Given a failed exec() syscall and its resulting errno
95
+ * value, print an appropriate error message to STDERR.
96
+ *
97
+ * This function is async signal-safe. Its main intended use is to be the
98
+ * default value for the `onExecFail` parameter for the
99
+ * `runCommand()` and `runCommandAndCaptureOutput()` functions.
100
+ */
101
+ void printExecError(const char **command, int errcode);
102
+ void printExecError2(const char **command, int errcode, char *buf, size_t size);
103
+
104
+
105
+ } // namespace Passenger
106
+
107
+ #endif /* _PASSENGER_PROCESS_MANAGEMENT_UTILS_H_ */
@@ -30,6 +30,7 @@
30
30
 
31
31
  #include <algorithm>
32
32
  #include <cassert>
33
+ #include <cstdio>
33
34
  #include <cstdlib>
34
35
  #include <cstring>
35
36
  #include <cerrno>
@@ -55,6 +56,8 @@
55
56
  #include <FileDescriptor.h>
56
57
  #include <ResourceLocator.h>
57
58
  #include <Exceptions.h>
59
+ #include <ProcessManagement/Spawn.h>
60
+ #include <ProcessManagement/Utils.h>
58
61
  #include <Utils.h>
59
62
  #include <Utils/CachedFileStat.hpp>
60
63
  #include <Utils/StrIntUtils.h>
@@ -69,16 +72,9 @@
69
72
  #define HOST_NAME_MAX 255
70
73
  #endif
71
74
  #endif
72
- #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
73
- // Introduced in Solaris 9. Let's hope nobody actually uses
74
- // a version that doesn't support this.
75
- #define HAS_CLOSEFROM
76
- #endif
77
75
 
78
76
  namespace Passenger {
79
77
 
80
- static string passengerTempDir;
81
-
82
78
  namespace {
83
79
  /**
84
80
  * Given a filename, FileGuard will unlink the file in its destructor, unless
@@ -717,54 +713,38 @@ makeDirTree(const string &path, const StaticString &mode, uid_t owner, gid_t gro
717
713
  }
718
714
  }
719
715
 
720
- void
721
- removeDirTree(const string &path) {
722
- boost::this_thread::disable_interruption di;
723
- boost::this_thread::disable_syscall_interruption dsi;
724
- const char *c_path = path.c_str();
725
- pid_t pid;
726
-
727
- pid = syscalls::fork();
728
- if (pid == 0) {
729
- resetSignalHandlersAndMask();
730
- disableMallocDebugging();
731
- int devnull = open("/dev/null", O_RDONLY);
732
- if (devnull != -1) {
733
- dup2(devnull, 2);
734
- }
735
- closeAllFileDescriptors(2);
736
- execlp("chmod", "chmod", "-R", "u+rwx", c_path, (char * const) 0);
737
- perror("Cannot execute chmod");
738
- _exit(1);
739
-
740
- } else if (pid == -1) {
741
- int e = errno;
742
- throw SystemException("Cannot fork a new process", e);
743
-
744
- } else {
745
- boost::this_thread::restore_interruption ri(di);
746
- boost::this_thread::restore_syscall_interruption rsi(dsi);
747
- syscalls::waitpid(pid, NULL, 0);
716
+ static void
717
+ redirectStderrToDevNull() {
718
+ int devnull = open("/dev/null", O_RDONLY);
719
+ if (devnull > 2) {
720
+ dup2(devnull, 2);
721
+ close(devnull);
748
722
  }
723
+ }
749
724
 
750
- pid = syscalls::fork();
751
- if (pid == 0) {
752
- resetSignalHandlersAndMask();
753
- disableMallocDebugging();
754
- closeAllFileDescriptors(2);
755
- execlp("rm", "rm", "-rf", c_path, (char * const) 0);
756
- perror("Cannot execute rm");
757
- _exit(1);
758
-
759
- } else if (pid == -1) {
760
- int e = errno;
761
- throw SystemException("Cannot fork a new process", e);
762
-
763
- } else {
764
- boost::this_thread::restore_interruption ri(di);
765
- boost::this_thread::restore_syscall_interruption rsi(dsi);
766
- int status;
767
- if (syscalls::waitpid(pid, &status, 0) == -1 || status != 0) {
725
+ void
726
+ removeDirTree(const string &path) {
727
+ {
728
+ const char *command[] = {
729
+ "chmod",
730
+ "-R",
731
+ "u+rwx",
732
+ path.c_str(),
733
+ NULL
734
+ };
735
+ SubprocessInfo info;
736
+ runCommand(command, info, true, true, redirectStderrToDevNull);
737
+ }
738
+ {
739
+ const char *command[] = {
740
+ "rm",
741
+ "-rf",
742
+ path.c_str(),
743
+ NULL
744
+ };
745
+ SubprocessInfo info;
746
+ runCommand(command, info, true, true, redirectStderrToDevNull);
747
+ if (info.status != 0 && info.status != -2) {
768
748
  throw RuntimeException("Cannot remove directory '" + path + "'");
769
749
  }
770
750
  }
@@ -782,8 +762,6 @@ prestartWebApps(const ResourceLocator &locator, const string &ruby,
782
762
  */
783
763
  syscalls::sleep(2);
784
764
 
785
- boost::this_thread::disable_interruption di;
786
- boost::this_thread::disable_syscall_interruption dsi;
787
765
  vector<string>::const_iterator it;
788
766
  string prespawnScript = locator.getHelperScriptsDir() + "/prespawn";
789
767
 
@@ -794,47 +772,15 @@ prestartWebApps(const ResourceLocator &locator, const string &ruby,
794
772
  continue;
795
773
  }
796
774
 
797
- pid_t pid;
775
+ const char *command[] = {
776
+ ruby.c_str(),
777
+ prespawnScript.c_str(),
778
+ it->c_str(),
779
+ NULL
780
+ };
781
+ SubprocessInfo info;
782
+ runCommand(command, info);
798
783
 
799
- pid = fork();
800
- if (pid == 0) {
801
- long max_fds, i;
802
- int e;
803
-
804
- // Close all unnecessary file descriptors.
805
- max_fds = sysconf(_SC_OPEN_MAX);
806
- for (i = 3; i < max_fds; i++) {
807
- syscalls::close(i);
808
- }
809
-
810
- execlp(ruby.c_str(),
811
- ruby.c_str(),
812
- prespawnScript.c_str(),
813
- it->c_str(),
814
- (char *) 0);
815
- e = errno;
816
- fprintf(stderr, "Cannot execute '%s %s %s': %s (%d)\n",
817
- ruby.c_str(),
818
- prespawnScript.c_str(), it->c_str(),
819
- strerror(e), e);
820
- fflush(stderr);
821
- _exit(1);
822
- } else if (pid == -1) {
823
- perror("fork()");
824
- } else {
825
- try {
826
- boost::this_thread::restore_interruption si(di);
827
- boost::this_thread::restore_syscall_interruption ssi(dsi);
828
- syscalls::waitpid(pid, NULL, 0);
829
- } catch (const thread_interrupted &) {
830
- syscalls::kill(SIGKILL, pid);
831
- syscalls::waitpid(pid, NULL, 0);
832
- throw;
833
- }
834
- }
835
-
836
- boost::this_thread::restore_interruption si(di);
837
- boost::this_thread::restore_syscall_interruption ssi(dsi);
838
784
  syscalls::sleep(1);
839
785
  it++;
840
786
  }
@@ -923,472 +869,6 @@ getSignalName(int sig) {
923
869
  }
924
870
  }
925
871
 
926
- void
927
- resetSignalHandlersAndMask() {
928
- struct sigaction action;
929
- action.sa_handler = SIG_DFL;
930
- action.sa_flags = SA_RESTART;
931
- sigemptyset(&action.sa_mask);
932
- sigaction(SIGHUP, &action, NULL);
933
- sigaction(SIGINT, &action, NULL);
934
- sigaction(SIGQUIT, &action, NULL);
935
- sigaction(SIGILL, &action, NULL);
936
- sigaction(SIGTRAP, &action, NULL);
937
- sigaction(SIGABRT, &action, NULL);
938
- #ifdef SIGEMT
939
- sigaction(SIGEMT, &action, NULL);
940
- #endif
941
- sigaction(SIGFPE, &action, NULL);
942
- sigaction(SIGBUS, &action, NULL);
943
- sigaction(SIGSEGV, &action, NULL);
944
- sigaction(SIGSYS, &action, NULL);
945
- sigaction(SIGPIPE, &action, NULL);
946
- sigaction(SIGALRM, &action, NULL);
947
- sigaction(SIGTERM, &action, NULL);
948
- sigaction(SIGURG, &action, NULL);
949
- sigaction(SIGSTOP, &action, NULL);
950
- sigaction(SIGTSTP, &action, NULL);
951
- sigaction(SIGCONT, &action, NULL);
952
- sigaction(SIGCHLD, &action, NULL);
953
- #ifdef SIGINFO
954
- sigaction(SIGINFO, &action, NULL);
955
- #endif
956
- sigaction(SIGUSR1, &action, NULL);
957
- sigaction(SIGUSR2, &action, NULL);
958
-
959
- // We reset the signal mask after resetting the signal handlers,
960
- // because prior to calling resetSignalHandlersAndMask(), the
961
- // process might be blocked on some signals. We want those signals
962
- // to be processed after installing the new signal handlers
963
- // so that bugs like https://github.com/phusion/passenger/pull/97
964
- // can be prevented.
965
-
966
- sigset_t signal_set;
967
- int ret;
968
-
969
- sigemptyset(&signal_set);
970
- do {
971
- ret = sigprocmask(SIG_SETMASK, &signal_set, NULL);
972
- } while (ret == -1 && errno == EINTR);
973
- }
974
-
975
- void
976
- disableMallocDebugging() {
977
- unsetenv("MALLOC_FILL_SPACE");
978
- unsetenv("MALLOC_PROTECT_BEFORE");
979
- unsetenv("MallocGuardEdges");
980
- unsetenv("MallocScribble");
981
- unsetenv("MallocPreScribble");
982
- unsetenv("MallocCheckHeapStart");
983
- unsetenv("MallocCheckHeapEach");
984
- unsetenv("MallocCheckHeapAbort");
985
- unsetenv("MallocBadFreeAbort");
986
- unsetenv("MALLOC_CHECK_");
987
-
988
- const char *libs = getenv("DYLD_INSERT_LIBRARIES");
989
- if (libs != NULL && strstr(libs, "/usr/lib/libgmalloc.dylib")) {
990
- string newLibs = libs;
991
- string::size_type pos = newLibs.find("/usr/lib/libgmalloc.dylib");
992
- size_t len = strlen("/usr/lib/libgmalloc.dylib");
993
-
994
- // Erase all leading ':' too.
995
- while (pos > 0 && newLibs[pos - 1] == ':') {
996
- pos--;
997
- len++;
998
- }
999
- // Erase all trailing ':' too.
1000
- while (pos + len < newLibs.size() && newLibs[pos + len] == ':') {
1001
- len++;
1002
- }
1003
-
1004
- newLibs.erase(pos, len);
1005
- if (newLibs.empty()) {
1006
- unsetenv("DYLD_INSERT_LIBRARIES");
1007
- } else {
1008
- setenv("DYLD_INSERT_LIBRARIES", newLibs.c_str(), 1);
1009
- }
1010
- }
1011
- }
1012
-
1013
- int
1014
- runShellCommand(const StaticString &command) {
1015
- pid_t pid = fork();
1016
- if (pid == 0) {
1017
- resetSignalHandlersAndMask();
1018
- disableMallocDebugging();
1019
- closeAllFileDescriptors(2);
1020
- execlp("/bin/sh", "/bin/sh", "-c", command.data(), (char * const) 0);
1021
- _exit(1);
1022
- } else if (pid == -1) {
1023
- return -1;
1024
- } else {
1025
- int status;
1026
- if (waitpid(pid, &status, 0) == -1) {
1027
- return -1;
1028
- } else {
1029
- return status;
1030
- }
1031
- }
1032
- }
1033
-
1034
- string
1035
- runCommandAndCaptureOutput(const char **command, int *status) {
1036
- pid_t pid, waitRet;
1037
- int e, waitStatus;
1038
- Pipe p;
1039
-
1040
- p = createPipe(__FILE__, __LINE__);
1041
-
1042
- boost::this_thread::disable_syscall_interruption dsi;
1043
- pid = syscalls::fork();
1044
- if (pid == 0) {
1045
- // Make ps nicer, we want to have as little impact on the rest
1046
- // of the system as possible while collecting the metrics.
1047
- int prio = getpriority(PRIO_PROCESS, getpid());
1048
- prio++;
1049
- if (prio > 20) {
1050
- prio = 20;
1051
- }
1052
- setpriority(PRIO_PROCESS, getpid(), prio);
1053
-
1054
- dup2(p[1], 1);
1055
- close(p[0]);
1056
- close(p[1]);
1057
- closeAllFileDescriptors(2);
1058
- execvp(command[0], (char * const *) command);
1059
- _exit(1);
1060
- } else if (pid == -1) {
1061
- e = errno;
1062
- throw SystemException("Cannot fork() a new process", e);
1063
- } else {
1064
- bool done = false;
1065
- string result;
1066
-
1067
- p[1].close();
1068
- while (!done) {
1069
- char buf[1024 * 4];
1070
- ssize_t ret;
1071
-
1072
- try {
1073
- boost::this_thread::restore_syscall_interruption rsi(dsi);
1074
- ret = syscalls::read(p[0], buf, sizeof(buf));
1075
- } catch (const thread_interrupted &) {
1076
- syscalls::kill(SIGKILL, pid);
1077
- syscalls::waitpid(pid, NULL, 0);
1078
- throw;
1079
- }
1080
- if (ret == -1) {
1081
- e = errno;
1082
- syscalls::kill(SIGKILL, pid);
1083
- syscalls::waitpid(pid, NULL, 0);
1084
- throw SystemException(string("Cannot read output from the '") +
1085
- command[0] + "' command", e);
1086
- }
1087
- done = ret == 0;
1088
- result.append(buf, ret);
1089
- }
1090
- p[0].close();
1091
-
1092
- waitRet = syscalls::waitpid(pid, &waitStatus, 0);
1093
- if (waitRet != -1) {
1094
- if (status != NULL) {
1095
- *status = waitStatus;
1096
- }
1097
- } else if (errno == ECHILD || errno == ESRCH) {
1098
- if (status != NULL) {
1099
- *status = -1;
1100
- }
1101
- } else {
1102
- int e = errno;
1103
- throw SystemException(string("Error waiting for the '") +
1104
- command[0] + "' command", e);
1105
- }
1106
- return result;
1107
- }
1108
- }
1109
-
1110
- #ifdef __APPLE__
1111
- // http://www.opensource.apple.com/source/Libc/Libc-825.26/sys/fork.c
1112
- // This bypasses atfork handlers.
1113
- extern "C" {
1114
- extern pid_t __fork(void);
1115
- }
1116
- #endif
1117
-
1118
- pid_t
1119
- asyncFork() {
1120
- #if defined(__linux__)
1121
- #if defined(SYS_fork)
1122
- return (pid_t) syscall(SYS_fork);
1123
- #else
1124
- return syscall(SYS_clone, SIGCHLD, 0, 0, 0, 0);
1125
- #endif
1126
- #elif defined(__APPLE__)
1127
- return __fork();
1128
- #else
1129
- return fork();
1130
- #endif
1131
- }
1132
-
1133
- // Async-signal safe way to get the current process's hard file descriptor limit.
1134
- static int
1135
- getFileDescriptorLimit() {
1136
- long long sysconfResult = sysconf(_SC_OPEN_MAX);
1137
-
1138
- struct rlimit rl;
1139
- long long rlimitResult;
1140
- if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
1141
- rlimitResult = 0;
1142
- } else {
1143
- rlimitResult = (long long) rl.rlim_max;
1144
- }
1145
-
1146
- long result;
1147
- // OS X 10.9 returns LLONG_MAX. It doesn't make sense
1148
- // to use that result so we limit ourselves to the
1149
- // sysconf result.
1150
- if (rlimitResult >= INT_MAX || sysconfResult > rlimitResult) {
1151
- result = sysconfResult;
1152
- } else {
1153
- result = rlimitResult;
1154
- }
1155
-
1156
- if (result < 0) {
1157
- // Unable to query the file descriptor limit.
1158
- result = 9999;
1159
- } else if (result < 2) {
1160
- // The calls reported broken values.
1161
- result = 2;
1162
- }
1163
- return result;
1164
- }
1165
-
1166
- // Async-signal safe function to get the highest file
1167
- // descriptor that the process is currently using.
1168
- // See also http://stackoverflow.com/questions/899038/getting-the-highest-allocated-file-descriptor
1169
- static int
1170
- getHighestFileDescriptor(bool asyncSignalSafe) {
1171
- #if defined(F_MAXFD)
1172
- int ret;
1173
-
1174
- do {
1175
- ret = fcntl(0, F_MAXFD);
1176
- } while (ret == -1 && errno == EINTR);
1177
- if (ret == -1) {
1178
- ret = getFileDescriptorLimit();
1179
- }
1180
- return ret;
1181
-
1182
- #else
1183
- int p[2], ret, flags;
1184
- pid_t pid = -1;
1185
- int result = -1;
1186
-
1187
- /* Since opendir() may not be async signal safe and thus may lock up
1188
- * or crash, we use it in a child process which we kill if we notice
1189
- * that things are going wrong.
1190
- */
1191
-
1192
- // Make a pipe.
1193
- p[0] = p[1] = -1;
1194
- do {
1195
- ret = pipe(p);
1196
- } while (ret == -1 && errno == EINTR);
1197
- if (ret == -1) {
1198
- goto done;
1199
- }
1200
-
1201
- // Make the read side non-blocking.
1202
- do {
1203
- flags = fcntl(p[0], F_GETFL);
1204
- } while (flags == -1 && errno == EINTR);
1205
- if (flags == -1) {
1206
- goto done;
1207
- }
1208
- do {
1209
- fcntl(p[0], F_SETFL, flags | O_NONBLOCK);
1210
- } while (ret == -1 && errno == EINTR);
1211
- if (ret == -1) {
1212
- goto done;
1213
- }
1214
-
1215
- if (asyncSignalSafe) {
1216
- do {
1217
- pid = asyncFork();
1218
- } while (pid == -1 && errno == EINTR);
1219
- } else {
1220
- do {
1221
- pid = fork();
1222
- } while (pid == -1 && errno == EINTR);
1223
- }
1224
-
1225
- if (pid == 0) {
1226
- // Don't close p[0] here or it might affect the result.
1227
-
1228
- resetSignalHandlersAndMask();
1229
-
1230
- struct sigaction action;
1231
- action.sa_handler = _exit;
1232
- action.sa_flags = SA_RESTART;
1233
- sigemptyset(&action.sa_mask);
1234
- sigaction(SIGSEGV, &action, NULL);
1235
- sigaction(SIGPIPE, &action, NULL);
1236
- sigaction(SIGBUS, &action, NULL);
1237
- sigaction(SIGILL, &action, NULL);
1238
- sigaction(SIGFPE, &action, NULL);
1239
- sigaction(SIGABRT, &action, NULL);
1240
-
1241
- DIR *dir = NULL;
1242
- #ifdef __APPLE__
1243
- /* /dev/fd can always be trusted on OS X. */
1244
- dir = opendir("/dev/fd");
1245
- #else
1246
- /* On FreeBSD and possibly other operating systems, /dev/fd only
1247
- * works if fdescfs is mounted. If it isn't mounted then /dev/fd
1248
- * still exists but always returns [0, 1, 2] and thus can't be
1249
- * trusted. If /dev and /dev/fd are on different filesystems
1250
- * then that probably means fdescfs is mounted.
1251
- */
1252
- struct stat dirbuf1, dirbuf2;
1253
- if (stat("/dev", &dirbuf1) == -1
1254
- || stat("/dev/fd", &dirbuf2) == -1) {
1255
- _exit(1);
1256
- }
1257
- if (dirbuf1.st_dev != dirbuf2.st_dev) {
1258
- dir = opendir("/dev/fd");
1259
- }
1260
- #endif
1261
- if (dir == NULL) {
1262
- dir = opendir("/proc/self/fd");
1263
- if (dir == NULL) {
1264
- _exit(1);
1265
- }
1266
- }
1267
-
1268
- struct dirent *ent;
1269
- union {
1270
- int highest;
1271
- char data[sizeof(int)];
1272
- } u;
1273
- u.highest = -1;
1274
-
1275
- while ((ent = readdir(dir)) != NULL) {
1276
- if (ent->d_name[0] != '.') {
1277
- int number = atoi(ent->d_name);
1278
- if (number > u.highest) {
1279
- u.highest = number;
1280
- }
1281
- }
1282
- }
1283
- if (u.highest != -1) {
1284
- ssize_t ret, written = 0;
1285
- do {
1286
- ret = write(p[1], u.data + written, sizeof(int) - written);
1287
- if (ret == -1) {
1288
- _exit(1);
1289
- }
1290
- written += ret;
1291
- } while (written < (ssize_t) sizeof(int));
1292
- }
1293
- closedir(dir);
1294
- _exit(0);
1295
-
1296
- } else if (pid == -1) {
1297
- goto done;
1298
-
1299
- } else {
1300
- close(p[1]); // Do not retry on EINTR: http://news.ycombinator.com/item?id=3363819
1301
- p[1] = -1;
1302
-
1303
- union {
1304
- int highest;
1305
- char data[sizeof(int)];
1306
- } u;
1307
- ssize_t ret, bytesRead = 0;
1308
- struct pollfd pfd;
1309
- pfd.fd = p[0];
1310
- pfd.events = POLLIN;
1311
-
1312
- do {
1313
- do {
1314
- // The child process must finish within 30 ms, otherwise
1315
- // we might as well query sysconf.
1316
- ret = poll(&pfd, 1, 30);
1317
- } while (ret == -1 && errno == EINTR);
1318
- if (ret <= 0) {
1319
- goto done;
1320
- }
1321
-
1322
- do {
1323
- ret = read(p[0], u.data + bytesRead, sizeof(int) - bytesRead);
1324
- } while (ret == -1 && errno == EINTR);
1325
- if (ret == -1) {
1326
- if (errno != EAGAIN) {
1327
- goto done;
1328
- }
1329
- } else if (ret == 0) {
1330
- goto done;
1331
- } else {
1332
- bytesRead += ret;
1333
- }
1334
- } while (bytesRead < (ssize_t) sizeof(int));
1335
-
1336
- result = u.highest;
1337
- goto done;
1338
- }
1339
-
1340
- done:
1341
- // Do not retry on EINTR: http://news.ycombinator.com/item?id=3363819
1342
- if (p[0] != -1) {
1343
- close(p[0]);
1344
- }
1345
- if (p[1] != -1) {
1346
- close(p[1]);
1347
- }
1348
- if (pid != -1) {
1349
- do {
1350
- ret = kill(pid, SIGKILL);
1351
- } while (ret == -1 && errno == EINTR);
1352
- do {
1353
- ret = waitpid(pid, NULL, 0);
1354
- } while (ret == -1 && errno == EINTR);
1355
- }
1356
-
1357
- if (result == -1) {
1358
- result = getFileDescriptorLimit();
1359
- }
1360
- return result;
1361
- #endif
1362
- }
1363
-
1364
- void
1365
- closeAllFileDescriptors(int lastToKeepOpen, bool asyncSignalSafe) {
1366
- #if defined(F_CLOSEM)
1367
- int ret;
1368
- do {
1369
- ret = fcntl(lastToKeepOpen + 1, F_CLOSEM);
1370
- } while (ret == -1 && errno == EINTR);
1371
- if (ret != -1) {
1372
- return;
1373
- }
1374
- #elif defined(HAS_CLOSEFROM)
1375
- closefrom(lastToKeepOpen + 1);
1376
- return;
1377
- #endif
1378
-
1379
- for (int i = getHighestFileDescriptor(asyncSignalSafe); i > lastToKeepOpen; i--) {
1380
- /* Even though we normally shouldn't retry on EINTR
1381
- * (http://news.ycombinator.com/item?id=3363819)
1382
- * it's okay to do that here because because this function
1383
- * may only be called in a single-threaded environment.
1384
- */
1385
- int ret;
1386
- do {
1387
- ret = close(i);
1388
- } while (ret == -1 && errno == EINTR);
1389
- }
1390
- }
1391
-
1392
872
  void
1393
873
  breakpoint() {
1394
874
  // No-op.