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