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.
- checksums.yaml +4 -4
- data/CHANGELOG +18 -0
- data/Rakefile +20 -17
- data/bin/passenger-install-apache2-module +14 -11
- data/build/agent.rb +45 -18
- data/build/apache2.rb +32 -16
- data/build/basics.rb +29 -40
- data/build/common_library.rb +70 -54
- data/build/cxx_tests.rb +34 -43
- data/build/integration_tests.rb +10 -10
- data/build/misc.rb +6 -6
- data/build/node_tests.rb +1 -2
- data/build/oxt_tests.rb +7 -5
- data/build/packaging.rb +11 -441
- data/build/ruby_extension.rb +1 -1
- data/build/ruby_tests.rb +1 -2
- data/build/support/cplusplus.rb +6 -5
- data/build/support/cxx_dependency_map.rb +357 -833
- data/build/support/general.rb +23 -1
- data/build/test_basics.rb +3 -28
- data/dev/ci/tests/rpm/Jenkinsfile +68 -0
- data/dev/ci/tests/rpm/run +63 -0
- data/dev/ci/tests/source-packaging/run +1 -1
- data/dev/ci/tests/source-packaging/setup +1 -1
- data/doc/{Packaging.txt.md → Packaging.md} +0 -0
- data/resources/templates/apache2/deployment_example.txt.erb +2 -2
- data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
- data/resources/templates/nginx/deployment_example.txt.erb +1 -1
- data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
- data/resources/templates/standalone/server.erb +2 -2
- data/src/agent/AgentMain.cpp +0 -4
- data/src/agent/Core/CoreMain.cpp +88 -5
- data/src/agent/Core/SpawningKit/Spawner.h +2 -1
- data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
- data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
- data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
- data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
- data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
- data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
- data/src/agent/Shared/Fundamentals/Utils.h +46 -0
- data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
- data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
- data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
- data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
- data/src/apache2_module/Hooks.cpp +4 -1
- data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
- data/src/cxx_supportlib/Constants.h +1 -2
- data/src/cxx_supportlib/Crypto.cpp +2 -1
- data/src/cxx_supportlib/Hooks.h +16 -37
- data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
- data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
- data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
- data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
- data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
- data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
- data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
- data/src/cxx_supportlib/Utils.cpp +41 -561
- data/src/cxx_supportlib/Utils.h +0 -68
- data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
- data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
- data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
- data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
- data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
- data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
- data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
- data/src/nginx_module/CacheLocationConfig.c +0 -75
- data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/Configuration.c +0 -1
- data/src/nginx_module/Configuration.h +0 -1
- data/src/nginx_module/ConfigurationCommands.c +1 -1
- data/src/nginx_module/ContentHandler.c +0 -1
- data/src/nginx_module/ContentHandler.h +0 -1
- data/src/nginx_module/CreateLocationConfig.c +0 -5
- data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/LocationConfig.h +0 -4
- data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
- data/src/nginx_module/MergeLocationConfig.c +0 -12
- data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/ngx_http_passenger_module.h +0 -1
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
- data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
- data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
- data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
- data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
- data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
- data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
- metadata +19 -97
- data/build/documentation.rb +0 -70
- data/doc/CloudLicensingConfiguration.html +0 -172
- data/doc/CloudLicensingConfiguration.txt.md +0 -3
- data/doc/Packaging.html +0 -488
- data/doc/Security of user switching support.idmap.txt +0 -34
- data/doc/Security of user switching support.txt +0 -197
- data/doc/ServerOptimizationGuide.html +0 -172
- data/doc/ServerOptimizationGuide.txt.md +0 -3
- data/doc/images/by_sa.png +0 -0
- data/doc/images/cloud_licensing_batch_job.png +0 -0
- data/doc/images/code_walkthrough.jpg +0 -0
- data/doc/images/direct_spawning.png +0 -0
- data/doc/images/direct_spawning.svg +0 -251
- data/doc/images/glyphicons-halflings-white.png +0 -0
- data/doc/images/glyphicons-halflings.png +0 -0
- data/doc/images/icons/README +0 -5
- data/doc/images/icons/callouts/1.png +0 -0
- data/doc/images/icons/callouts/10.png +0 -0
- data/doc/images/icons/callouts/11.png +0 -0
- data/doc/images/icons/callouts/12.png +0 -0
- data/doc/images/icons/callouts/13.png +0 -0
- data/doc/images/icons/callouts/14.png +0 -0
- data/doc/images/icons/callouts/15.png +0 -0
- data/doc/images/icons/callouts/2.png +0 -0
- data/doc/images/icons/callouts/3.png +0 -0
- data/doc/images/icons/callouts/4.png +0 -0
- data/doc/images/icons/callouts/5.png +0 -0
- data/doc/images/icons/callouts/6.png +0 -0
- data/doc/images/icons/callouts/7.png +0 -0
- data/doc/images/icons/callouts/8.png +0 -0
- data/doc/images/icons/callouts/9.png +0 -0
- data/doc/images/icons/caution.png +0 -0
- data/doc/images/icons/example.png +0 -0
- data/doc/images/icons/home.png +0 -0
- data/doc/images/icons/important.png +0 -0
- data/doc/images/icons/next.png +0 -0
- data/doc/images/icons/note.png +0 -0
- data/doc/images/icons/prev.png +0 -0
- data/doc/images/icons/tip.png +0 -0
- data/doc/images/icons/up.png +0 -0
- data/doc/images/icons/warning.png +0 -0
- data/doc/images/many_web_framework_protocols.png +0 -0
- data/doc/images/passenger_architecture.png +0 -0
- data/doc/images/passenger_architecture.svg +0 -385
- data/doc/images/passenger_architecture_overview.png +0 -0
- data/doc/images/passenger_core_architecture.png +0 -0
- data/doc/images/passenger_nodejs_architecture.svg +0 -558
- data/doc/images/phusion_banner.png +0 -0
- data/doc/images/rack.png +0 -0
- data/doc/images/smart_spawning.png +0 -0
- data/doc/images/smart_spawning.svg +0 -323
- data/doc/images/spawn_server_architecture.png +0 -0
- data/doc/images/spawn_server_architecture.svg +0 -655
- data/doc/images/spawning_preparation_work.png +0 -0
- data/doc/images/startup_sequence.png +0 -0
- data/doc/images/typical_isolated_web_application.png +0 -0
- data/doc/images/typical_isolated_web_application.svg +0 -213
- data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
- data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
- data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
- data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
- data/doc/users_guide_snippets/deployment_basics.txt +0 -37
- data/doc/users_guide_snippets/enterprise_only.txt +0 -1
- data/doc/users_guide_snippets/environment_variables.txt +0 -44
- data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
- data/doc/users_guide_snippets/installation.txt +0 -228
- data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
- data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
- data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
- data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
- data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
- data/doc/users_guide_snippets/since_version.txt +0 -1
- data/doc/users_guide_snippets/support_information.txt +0 -8
- data/doc/users_guide_snippets/tips.txt +0 -302
- data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
- data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
- data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
- data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
- data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
- data/src/agent/Shared/Base.cpp +0 -1678
- data/src/agent/UstRouter/ApiServer.h +0 -292
- data/src/agent/UstRouter/Client.h +0 -112
- data/src/agent/UstRouter/Controller.h +0 -1309
- data/src/agent/UstRouter/LogSink.h +0 -145
- data/src/agent/UstRouter/OptionParser.h +0 -180
- data/src/agent/UstRouter/RemoteSender.h +0 -853
- data/src/agent/UstRouter/RemoteSink.h +0 -145
- data/src/agent/UstRouter/Transaction.h +0 -278
- data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
- data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
- 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
|