2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/debugger/dummy_sandbox.h"
19 #include <boost/noncopyable.hpp>
21 #include "hphp/runtime/debugger/debugger.h"
22 #include "hphp/runtime/debugger/cmd/cmd_signal.h"
23 #include "hphp/runtime/base/program-functions.h"
24 #include "hphp/runtime/server/source_root_info.h"
25 #include "hphp/runtime/base/externals.h"
26 #include "hphp/runtime/base/hphp_system.h"
27 #include "hphp/util/logger.h"
28 #include "hphp/util/process.h"
30 namespace HPHP
{ namespace Eval
{
31 ///////////////////////////////////////////////////////////////////////////////
32 TRACE_SET_MOD(debugger
);
34 DummySandbox::DummySandbox(DebuggerProxy
*proxy
,
35 const std::string
&defaultPath
,
36 const std::string
&startupFile
)
37 : m_proxy(proxy
), m_defaultPath(defaultPath
), m_startupFile(startupFile
),
38 m_thread(this, &DummySandbox::run
), m_stopped(false),
39 m_signum(CmdSignal::SignalNone
) { }
41 void DummySandbox::start() {
42 TRACE(2, "DummySandbox::start\n");
46 // Stop the sandbox thread, and wait for it to end. Timeout is in
47 // seconds. This can be called multiple times.
48 bool DummySandbox::stop(int timeout
) {
49 TRACE(2, "DummySandbox::stop\n");
51 notify(); // Wakeup the sandbox thread so it will notice the stopped flag
52 return m_thread
.waitForEnd(timeout
);
57 struct CLISession
: private boost::noncopyable
{
59 TRACE(2, "CLISession::CLISession\n");
60 char *argv
[] = {"", nullptr};
61 execute_command_line_begin(1, argv
, 0);
64 TRACE(2, "CLISession::~CLISession\n");
65 Debugger::UnregisterSandbox(g_context
->getSandboxId());
66 ThreadInfo::s_threadInfo
.getNoCheck()->
67 m_reqInjectionData
.setDebugger(false);
68 execute_command_line_end(0, false, nullptr);
74 const StaticString
s__SERVER("_SERVER");
76 void DummySandbox::run() {
77 TRACE(2, "DummySandbox::run\n");
78 ThreadInfo
*ti
= ThreadInfo::s_threadInfo
.getNoCheck();
79 Debugger::RegisterThread();
82 CLISession hphpSession
;
84 DSandboxInfo sandbox
= m_proxy
->getSandbox();
86 if (sandbox
.valid()) {
87 GlobalVariables
*g
= get_global_variables();
88 SourceRootInfo
sri(sandbox
.m_user
, sandbox
.m_name
);
89 if (sandbox
.m_path
.empty()) {
90 sandbox
.m_path
= sri
.path();
92 if (!sri
.sandboxOn()) {
93 msg
= "Invalid sandbox was specified. "
94 "PHP files may not be loaded properly.\n";
96 sri
.setServerVariables(g
->getRef(s__SERVER
));
98 Debugger::RegisterSandbox(sandbox
);
99 g_context
->setSandboxId(sandbox
.id());
101 std::string doc
= getStartupDoc(sandbox
);
104 getcwd(cwd
, sizeof(cwd
));
105 Logger::Info("Start loading startup doc '%s', pwd = '%s'",
107 bool error
; string errorMsg
;
108 bool ret
= hphp_invoke(g_context
.getNoCheck(), doc
, false, null_array
,
109 uninit_null(), "", "", error
, errorMsg
, true,
112 msg
+= "Unable to pre-load " + doc
;
113 if (!errorMsg
.empty()) {
114 msg
+= ": " + errorMsg
;
117 Logger::Info("Startup doc " + doc
+ " loaded");
120 g_context
->setSandboxId(m_proxy
->getDummyInfo().id());
123 ti
->m_reqInjectionData
.setDebugger(true);
125 DebuggerDummyEnv dde
;
126 // This is really the entire point of having the dummy sandbox. This
127 // fires the initial session started interrupt to the client after
128 // it first attaches.
129 Debugger::InterruptSessionStarted(nullptr, msg
.c_str());
132 // Blocking until Ctrl-C is issued by end user and DebuggerProxy cannot
133 // find a real sandbox thread to handle it.
136 while (!m_stopped
&& m_signum
!= CmdSignal::SignalBreak
) {
140 // stopped by worker thread
143 m_signum
= CmdSignal::SignalNone
;
145 } catch (const DebuggerClientExitException
&e
) {
146 // stopped by the dummy sandbox thread itself
148 } catch (const DebuggerException
&e
) {
153 void DummySandbox::notifySignal(int signum
) {
154 TRACE(2, "DummySandbox::notifySignal\n");
160 std::string
DummySandbox::getStartupDoc(const DSandboxInfo
&sandbox
) {
161 TRACE(2, "DummySandbox::getStartupDoc\n");
163 if (!m_startupFile
.empty()) {
164 // if relative path, prepend directory
165 if (m_startupFile
[0] != '/' && m_startupFile
[0] != '~') {
166 path
= sandbox
.m_path
;
168 path
= m_defaultPath
;
171 if (!path
.empty() && path
[path
.size() - 1] != '/') {
174 path
+= m_startupFile
;
176 // resolving home directory
177 if (path
[0] == '~') {
179 size_t pos
= path
.find('/');
180 if (pos
== string::npos
) pos
= path
.size();
182 user
= path
.substr(1, pos
- 1);
184 if (user
.empty()) user
= sandbox
.m_user
;
185 if (user
.empty() || user
== Process::GetCurrentUser()) {
186 home
= Process::GetHomeDirectory();
188 home
= "/home/" + user
+ "/";
190 if (pos
+ 1 < path
.size()) {
191 path
= home
+ path
.substr(pos
+ 1);
200 ///////////////////////////////////////////////////////////////////////////////