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,106 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 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
+ #include <string>
28
+ #include <vector>
29
+ #include <cstddef>
30
+ #include <cstdio>
31
+
32
+ #include <ProcessManagement/Spawn.h>
33
+ #include <ProcessManagement/Ruby.h>
34
+ #include <ResourceLocator.h>
35
+ #include <Exceptions.h>
36
+
37
+ namespace Passenger {
38
+
39
+ using namespace std;
40
+
41
+
42
+ void
43
+ runInternalRubyTool(const ResourceLocator &resourceLocator,
44
+ const string &ruby, const vector<string> &args, int *status,
45
+ string *output)
46
+ {
47
+ string locationConfigFileEnv = "PASSENGER_LOCATION_CONFIGURATION_FILE="
48
+ + resourceLocator.getInstallSpec();
49
+ string fullProgramPath;
50
+ bool isRubyProgram;
51
+ const char *command[
52
+ 4 // env, locationConfigEnvFile, ruby, fullProgramPath
53
+ + (args.size() - 1)
54
+ + 1 // NULL
55
+ ];
56
+ unsigned int i = 0, j;
57
+
58
+ if (args[0][0] == '/') {
59
+ fullProgramPath = args[0];
60
+ } else {
61
+ fullProgramPath = resourceLocator.getBinDir() + "/" + args[0];
62
+ }
63
+
64
+ // The tool may be a wrapper script, e.g. one generated by Homebrew.
65
+ // If it's a non-Ruby wrapper script then don't invoke it with Ruby.
66
+ FILE *f = fopen(fullProgramPath.c_str(), "r");
67
+ if (f == NULL) {
68
+ throw RuntimeException("Unable to open " + fullProgramPath);
69
+ }
70
+ char line[1024];
71
+ if (fgets(line, sizeof(line), f) == NULL) {
72
+ if (ferror(f) != 0) {
73
+ fclose(f);
74
+ throw RuntimeException("Unable to read " + fullProgramPath);
75
+ } else {
76
+ throw RuntimeException(fullProgramPath + " is empty");
77
+ }
78
+ } else {
79
+ isRubyProgram = strstr(line, "ruby") != NULL;
80
+ }
81
+ fclose(f);
82
+
83
+ command[i++] = "env";
84
+ command[i++] = locationConfigFileEnv.c_str();
85
+ if (isRubyProgram) {
86
+ command[i++] = ruby.c_str();
87
+ }
88
+ command[i++] = fullProgramPath.c_str();
89
+ for (j = 1; j < args.size(); j++) {
90
+ command[i++] = args[j].c_str();
91
+ }
92
+ command[i++] = NULL;
93
+
94
+ SubprocessInfo info;
95
+ if (output == NULL) {
96
+ runCommand(command, info);
97
+ } else {
98
+ runCommandAndCaptureOutput(command, info, *output);
99
+ }
100
+ if (status != NULL) {
101
+ *status = info.status;
102
+ }
103
+ }
104
+
105
+
106
+ } // namespace Passenger
@@ -23,63 +23,39 @@
23
23
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
24
  * THE SOFTWARE.
25
25
  */
26
- #ifndef _PASSENGER_UST_ROUTER_FILE_SINK_H_
27
- #define _PASSENGER_UST_ROUTER_FILE_SINK_H_
26
+ #ifndef _PASSENGER_PROCESS_MANAGEMENT_RUBY_H_
27
+ #define _PASSENGER_PROCESS_MANAGEMENT_RUBY_H_
28
28
 
29
29
  #include <string>
30
- #include <ctime>
31
- #include <oxt/system_calls.hpp>
32
- #include <Exceptions.h>
33
- #include <FileDescriptor.h>
34
- #include <UstRouter/LogSink.h>
35
- #include <Utils/StrIntUtils.h>
30
+ #include <vector>
31
+ #include <cstddef>
36
32
 
37
33
  namespace Passenger {
38
- namespace UstRouter {
39
34
 
40
35
  using namespace std;
41
- using namespace oxt;
42
36
 
37
+ class ResourceLocator;
43
38
 
44
- class FileSink: public LogSink {
45
- public:
46
- string filename;
47
- FileDescriptor fd;
48
39
 
49
- FileSink(Controller *controller, const string &_filename)
50
- : LogSink(controller),
51
- filename(_filename)
52
- {
53
- fd.assign(syscalls::open(_filename.c_str(),
54
- O_CREAT | O_WRONLY | O_APPEND,
55
- 0600), __FILE__, __LINE__);
56
- if (fd == -1) {
57
- int e = errno;
58
- throw FileSystemException("Cannnot open file '" +
59
- filename + "' for appending", e, filename);
60
- }
61
- }
62
-
63
- virtual void append(const TransactionPtr &transaction) {
64
- StaticString data = transaction->getBody();
65
- LogSink::append(transaction);
66
- syscalls::write(fd, data.data(), data.size());
67
- }
68
-
69
- virtual Json::Value inspectStateAsJson() const {
70
- Json::Value doc = LogSink::inspectStateAsJson();
71
- doc["type"] = "file";
72
- doc["filename"] = filename;
73
- return doc;
74
- }
75
-
76
- string inspect() const {
77
- return "FileSink(" + filename + ")";
78
- }
79
- };
40
+ /**
41
+ * Run a Passenger-internal Ruby tool, e.g. passenger-config, and optionally capture
42
+ * its stdout output. This function does not care whether the command fails.
43
+ *
44
+ * @param resourceLocator
45
+ * @param ruby The Ruby interpreter to attempt to use for running the tool.
46
+ * @param args The command as an array of strings, e.g. ["passenger-config", "system-properties"].
47
+ * @param status The status of the child process will be stored here, if non-NULL.
48
+ * When unable to waitpid() the child process because of an ECHILD
49
+ * or ESRCH, this will be set to -1.
50
+ * @param output The output of the child process will be stored here, if non-NULL.
51
+ * @throws RuntimeException
52
+ * @throws SystemException
53
+ */
54
+ void runInternalRubyTool(const ResourceLocator &resourceLocator,
55
+ const string &ruby, const vector<string> &args,
56
+ int *status = NULL, string *output = NULL);
80
57
 
81
58
 
82
- } // namespace UstRouter
83
59
  } // namespace Passenger
84
60
 
85
- #endif /* _PASSENGER_UST_ROUTER_FILE_SINK_H_ */
61
+ #endif /* _PASSENGER_PROCESS_MANAGEMENT_RUBY_H_ */
@@ -0,0 +1,199 @@
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
+ #include <sys/types.h>
28
+ #include <sys/wait.h>
29
+ #include <unistd.h>
30
+ #include <stdlib.h>
31
+ #include <signal.h>
32
+
33
+ #include <boost/thread.hpp>
34
+ #include <oxt/system_calls.hpp>
35
+ #include <string>
36
+ #include <cerrno>
37
+
38
+ #include <ProcessManagement/Spawn.h>
39
+ #include <ProcessManagement/Utils.h>
40
+ #include <StaticString.h>
41
+ #include <Exceptions.h>
42
+ #include <Utils/IOUtils.h>
43
+
44
+ namespace Passenger {
45
+
46
+ using namespace std;
47
+
48
+
49
+ int
50
+ runShellCommand(const StaticString &command) {
51
+ string commandNt = command;
52
+ const char *argv[] = {
53
+ "/bin/sh",
54
+ "-c",
55
+ commandNt.c_str(),
56
+ NULL
57
+ };
58
+ SubprocessInfo info;
59
+ runCommand(argv, info);
60
+ return info.status;
61
+ }
62
+
63
+ void
64
+ runCommand(const char **command, SubprocessInfo &info, bool wait, bool killSubprocessOnInterruption,
65
+ const boost::function<void ()> &afterFork,
66
+ const boost::function<void (const char **, int errcode)> &onExecFail)
67
+ {
68
+ int e, waitStatus;
69
+ pid_t waitRet;
70
+
71
+ info.pid = asyncFork();
72
+ if (info.pid == 0) {
73
+ resetSignalHandlersAndMask();
74
+ disableMallocDebugging();
75
+ if (afterFork) {
76
+ afterFork();
77
+ }
78
+ closeAllFileDescriptors(2, true);
79
+ execvp(command[0], (char * const *) command);
80
+ if (onExecFail) {
81
+ onExecFail(command, errno);
82
+ }
83
+ _exit(1);
84
+ } else if (info.pid == -1) {
85
+ e = errno;
86
+ throw SystemException("Cannot fork() a new process", e);
87
+ } else if (wait) {
88
+ try {
89
+ waitRet = syscalls::waitpid(info.pid, &waitStatus, 0);
90
+ } catch (const boost::thread_interrupted &) {
91
+ if (killSubprocessOnInterruption) {
92
+ boost::this_thread::disable_syscall_interruption dsi;
93
+ syscalls::kill(SIGKILL, info.pid);
94
+ syscalls::waitpid(info.pid, NULL, 0);
95
+ }
96
+ throw;
97
+ }
98
+
99
+ if (waitRet != -1) {
100
+ info.status = waitStatus;
101
+ } else if (errno == ECHILD || errno == ESRCH) {
102
+ info.status = -2;
103
+ } else {
104
+ int e = errno;
105
+ throw SystemException(string("Error waiting for the '") +
106
+ command[0] + "' command", e);
107
+ }
108
+ }
109
+ }
110
+
111
+ void
112
+ runCommandAndCaptureOutput(const char **command, SubprocessInfo &info,
113
+ string &output, bool killSubprocessOnInterruption,
114
+ const boost::function<void ()> &afterFork,
115
+ const boost::function<void (const char **command, int errcode)> &onExecFail)
116
+ {
117
+ pid_t waitRet;
118
+ int e, waitStatus;
119
+ Pipe p;
120
+
121
+ p = createPipe(__FILE__, __LINE__);
122
+
123
+ info.pid = asyncFork();
124
+ if (info.pid == 0) {
125
+ dup2(p[1], 1);
126
+ close(p[0]);
127
+ close(p[1]);
128
+ resetSignalHandlersAndMask();
129
+ disableMallocDebugging();
130
+ if (afterFork) {
131
+ afterFork();
132
+ }
133
+ closeAllFileDescriptors(2, true);
134
+ execvp(command[0], (char * const *) command);
135
+ if (onExecFail) {
136
+ onExecFail(command, errno);
137
+ }
138
+ _exit(1);
139
+ } else if (info.pid == -1) {
140
+ e = errno;
141
+ throw SystemException("Cannot fork() a new process", e);
142
+ } else {
143
+ bool done = false;
144
+
145
+ p[1].close();
146
+ while (!done) {
147
+ char buf[1024 * 4];
148
+ ssize_t ret;
149
+
150
+ try {
151
+ ret = syscalls::read(p[0], buf, sizeof(buf));
152
+ } catch (const boost::thread_interrupted &) {
153
+ if (killSubprocessOnInterruption) {
154
+ boost::this_thread::disable_syscall_interruption dsi;
155
+ syscalls::kill(SIGKILL, info.pid);
156
+ syscalls::waitpid(info.pid, NULL, 0);
157
+ }
158
+ throw;
159
+ }
160
+ if (ret == -1) {
161
+ e = errno;
162
+ if (killSubprocessOnInterruption) {
163
+ boost::this_thread::disable_syscall_interruption dsi;
164
+ syscalls::kill(SIGKILL, info.pid);
165
+ syscalls::waitpid(info.pid, NULL, 0);
166
+ }
167
+ throw SystemException(string("Cannot read output from the '") +
168
+ command[0] + "' command", e);
169
+ }
170
+ done = ret == 0;
171
+ output.append(buf, ret);
172
+ }
173
+ p[0].close();
174
+
175
+ try {
176
+ waitRet = syscalls::waitpid(info.pid, &waitStatus, 0);
177
+ } catch (const boost::thread_interrupted &) {
178
+ if (killSubprocessOnInterruption) {
179
+ boost::this_thread::disable_syscall_interruption dsi;
180
+ syscalls::kill(SIGKILL, info.pid);
181
+ syscalls::waitpid(info.pid, NULL, 0);
182
+ }
183
+ throw;
184
+ }
185
+
186
+ if (waitRet != -1) {
187
+ info.status = waitStatus;
188
+ } else if (errno == ECHILD || errno == ESRCH) {
189
+ info.status = -2;
190
+ } else {
191
+ int e = errno;
192
+ throw SystemException(string("Error waiting for the '") +
193
+ command[0] + "' command", e);
194
+ }
195
+ }
196
+ }
197
+
198
+
199
+ } // namespace Passenger
@@ -0,0 +1,150 @@
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_SPAWN_H_
27
+ #define _PASSENGER_PROCESS_MANAGEMENT_SPAWN_H_
28
+
29
+ #include <sys/types.h>
30
+ #include <boost/function.hpp>
31
+ #include <string>
32
+ #include <StaticString.h>
33
+
34
+ namespace Passenger {
35
+
36
+ using namespace std;
37
+
38
+ struct SubprocessInfo {
39
+ /**
40
+ * The PID of the subprocess. This is set to -1 on
41
+ * object creation. If fork fails or is interrupted,
42
+ * then this field is unmodified.
43
+ *
44
+ * Attention: if you called `runCommand()` with `wait = true`,
45
+ * or if you called `runCommandAndCaptureOutput()`,
46
+ * then when that function returns, this PID no longer
47
+ * exists.
48
+ */
49
+ pid_t pid;
50
+
51
+ /**
52
+ * The status of the subprocess, as returned by waitpid().
53
+ * This is set to -1 on object creation.
54
+ *
55
+ * Only if `runCommand()` is done waiting for the subprocess
56
+ * will this field be set. So if you call `runCommand()` with
57
+ * `wait = false` then this field will never be modified.
58
+ *
59
+ * When unable to waitpid() the subprocess because of
60
+ * an ECHILD or ESRCH, then this field is set to -2.
61
+ */
62
+ int status;
63
+
64
+ SubprocessInfo()
65
+ : pid(-1),
66
+ status(-1)
67
+ { }
68
+ };
69
+
70
+
71
+ // See ProcessManagement/Utils.h for definition
72
+ void printExecError(const char **command, int errcode);
73
+
74
+ /**
75
+ * Like system(), but properly resets the signal handler mask,
76
+ * disables malloc debugging and closes file descriptors > 2.
77
+ *
78
+ * This is like `runCommand()` but runs something through the shell.
79
+ *
80
+ * @throws SystemException
81
+ * @throws boost::thread_interrupted
82
+ */
83
+ int runShellCommand(const StaticString &command);
84
+
85
+ /**
86
+ * Run a command and (if so configured) wait for it. You can see this function
87
+ * as a more flexible version of system(): it accepts a command array
88
+ * instead of a shell command string, and you can choose whether to wait
89
+ * for the subprocess or not.
90
+ *
91
+ * In addition, this function also properly resets the signal handler mask,
92
+ * disables malloc debugging and closes file descriptors > 2.
93
+ *
94
+ * Information about the subprocess is stored inside `info`. See the comments
95
+ * for the `SubprocessInfo` structure to learn more about it.
96
+ *
97
+ * If this function encounters an error or is interrupted, then it ensures
98
+ * that as much information as possible about the current state of things
99
+ * is stored in `info` so that the caller can clean things up appropriately.
100
+ *
101
+ * @param command The argument array to pass to execvp(). Must be null-terminated.
102
+ * @param info
103
+ * @param wait Whether to wait for the subprocess before returning.
104
+ * @param killSubprocessOnInterruption Whether to automatically kill the subprocess
105
+ * when this function is interrupted.
106
+ * @param afterFork A function object to be called right after forking.
107
+ * @throws SystemException
108
+ * @throws boost::thread_interrupted
109
+ */
110
+ void runCommand(const char **command, SubprocessInfo &info,
111
+ bool wait = true, bool killSubprocessOnInterruption = true,
112
+ const boost::function<void ()> &afterFork = boost::function<void ()>(),
113
+ const boost::function<void (const char **command, int errcode)> &onExecFail = printExecError);
114
+
115
+ /**
116
+ * Run a command, wait for it, and capture its stdout output.
117
+ * This function does not care whether the command fails.
118
+ *
119
+ * In addition (like `runCommand()`), this function also properly
120
+ * resets the signal handler mask, disables malloc debugging and
121
+ * closes file descriptors > 2.
122
+ *
123
+ * If something goes wrong or when interrupted while capturing the
124
+ * output, then `output` contains the output captured so far.
125
+ *
126
+ * Information about the subprocess is stored inside `info`. See the comments
127
+ * for the `SubprocessInfo` structure to learn more about it.
128
+ *
129
+ * If this function encounters an error or is interrupted, then it ensures
130
+ * that as much information as possible about the current state of things
131
+ * is stored in `info` so that the caller can clean things up appropriately.
132
+ *
133
+ * @param command The argument array to pass to execvp(). Must be null-terminated.
134
+ * @param info
135
+ * @param killSubprocessOnInterruption Whether to automatically kill the subprocess
136
+ * when this function is interrupted.
137
+ * @param afterFork A function object to be called right after forking.
138
+ * @param onExecFail A function object to be called if exec fails.
139
+ * @throws SystemException
140
+ * @throws boost::thread_interrupted
141
+ */
142
+ void runCommandAndCaptureOutput(const char **command, SubprocessInfo &info,
143
+ string &output, bool killSubprocessOnInterruption = true,
144
+ const boost::function<void ()> &afterFork = boost::function<void ()>(),
145
+ const boost::function<void (const char **command, int errcode)> &onExecFail = printExecError);
146
+
147
+
148
+ } // namespace Passenger
149
+
150
+ #endif /* _PASSENGER_PROCESS_MANAGEMENT_SPAWN_H_ */