OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/setup/daemon_controller_delegate_linux.h" | 5 #include "remoting/host/setup/daemon_controller_delegate_linux.h" |
6 | 6 |
7 #include <unistd.h> | 7 #include <unistd.h> |
8 | 8 |
9 #include "base/base_paths.h" | 9 #include "base/base_paths.h" |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 if (access(candidate_exe.value().c_str(), X_OK) == 0) { | 58 if (access(candidate_exe.value().c_str(), X_OK) == 0) { |
59 *result = candidate_exe; | 59 *result = candidate_exe; |
60 return true; | 60 return true; |
61 } | 61 } |
62 return false; | 62 return false; |
63 } | 63 } |
64 | 64 |
65 bool RunHostScriptWithTimeout( | 65 bool RunHostScriptWithTimeout( |
66 const std::vector<std::string>& args, | 66 const std::vector<std::string>& args, |
67 base::TimeDelta timeout, | 67 base::TimeDelta timeout, |
68 int* exit_code) { | 68 const DaemonController::ErrorCallback& on_error) { |
69 DCHECK(exit_code); | |
70 | 69 |
71 // As long as we're relying on running an external binary from the | 70 // As long as we're relying on running an external binary from the |
72 // PATH, don't do it as root. | 71 // PATH, don't do it as root. |
73 if (getuid() == 0) { | 72 if (getuid() == 0) { |
74 LOG(ERROR) << "Refusing to run script as root."; | 73 std::string error_message = "Refusing to run script as root"; |
| 74 LOG(ERROR) << error_message; |
| 75 on_error.Run(error_message, FROM_HERE); |
75 return false; | 76 return false; |
76 } | 77 } |
| 78 |
77 base::FilePath script_path; | 79 base::FilePath script_path; |
78 if (!GetScriptPath(&script_path)) { | 80 if (!GetScriptPath(&script_path)) { |
79 LOG(ERROR) << "GetScriptPath() failed."; | 81 std::string error_message = "GetScriptPath() failed"; |
| 82 LOG(ERROR) << error_message; |
| 83 on_error.Run(error_message, FROM_HERE); |
80 return false; | 84 return false; |
81 } | 85 } |
| 86 |
82 base::CommandLine command_line(script_path); | 87 base::CommandLine command_line(script_path); |
83 for (unsigned int i = 0; i < args.size(); ++i) { | 88 for (unsigned int i = 0; i < args.size(); ++i) { |
84 command_line.AppendArg(args[i]); | 89 command_line.AppendArg(args[i]); |
85 } | 90 } |
86 | 91 |
87 // Redirect the child's stdout to the parent's stderr. In the case where this | 92 // Redirect the child's stdout to the parent's stderr. In the case where this |
88 // parent process is a Native Messaging host, its stdout is used to send | 93 // parent process is a Native Messaging host, its stdout is used to send |
89 // messages to the web-app. | 94 // messages to the web-app. |
90 base::FileHandleMappingVector fds_to_remap; | 95 base::FileHandleMappingVector fds_to_remap; |
91 fds_to_remap.push_back(std::pair<int, int>(STDERR_FILENO, STDOUT_FILENO)); | 96 fds_to_remap.push_back(std::pair<int, int>(STDERR_FILENO, STDOUT_FILENO)); |
92 base::LaunchOptions options; | 97 base::LaunchOptions options; |
93 options.fds_to_remap = &fds_to_remap; | 98 options.fds_to_remap = &fds_to_remap; |
94 | 99 |
95 #if !defined(OS_CHROMEOS) | 100 #if !defined(OS_CHROMEOS) |
96 options.allow_new_privs = true; | 101 options.allow_new_privs = true; |
97 #endif | 102 #endif |
98 | 103 |
99 base::Process process = base::LaunchProcess(command_line, options); | 104 base::Process process = base::LaunchProcess(command_line, options); |
100 if (!process.IsValid()) { | 105 if (!process.IsValid()) { |
101 LOG(ERROR) << "Failed to run command: " | 106 std::ostringstream error_message; |
102 << command_line.GetCommandLineString(); | 107 error_message << "Failed to run command: " |
| 108 << command_line.GetCommandLineString(); |
| 109 LOG(ERROR) << error_message; |
| 110 on_error.Run(error_message.str(), FROM_HERE); |
103 return false; | 111 return false; |
104 } | 112 } |
105 | 113 |
106 if (!process.WaitForExitWithTimeout(timeout, exit_code)) { | 114 int exit_code; |
| 115 if (!process.WaitForExitWithTimeout(timeout, &exit_code)) { |
107 process.Terminate(0, false); | 116 process.Terminate(0, false); |
108 LOG(ERROR) << "Timeout exceeded for command: " | 117 std::ostringstream error_message; |
109 << command_line.GetCommandLineString(); | 118 error_message << "Timeout exceeded for command: " |
| 119 << command_line.GetCommandLineString(); |
| 120 LOG(ERROR) << error_message; |
| 121 on_error.Run(error_message.str(), FROM_HERE); |
110 return false; | 122 return false; |
111 } | 123 } |
112 | 124 |
| 125 if (exit_code != 0) { |
| 126 std::ostringstream error_message; |
| 127 error_message << "Non-zero exit code " << exit_code << " from command: " |
| 128 << command_line.GetCommandLineString(); |
| 129 LOG(ERROR) << error_message; |
| 130 on_error.Run(error_message.str(), FROM_HERE); |
| 131 } |
| 132 |
113 return true; | 133 return true; |
114 } | 134 } |
115 | 135 |
116 bool RunHostScript(const std::vector<std::string>& args, int* exit_code) { | 136 bool RunHostScript(const std::vector<std::string>& args, |
| 137 const DaemonController::ErrorCallback& on_error) { |
117 return RunHostScriptWithTimeout( | 138 return RunHostScriptWithTimeout( |
118 args, base::TimeDelta::FromMilliseconds(kDaemonTimeoutMs), exit_code); | 139 args, |
| 140 base::TimeDelta::FromMilliseconds(kDaemonTimeoutMs), |
| 141 on_error); |
119 } | 142 } |
120 | 143 |
121 } // namespace | 144 } // namespace |
122 | 145 |
123 DaemonControllerDelegateLinux::DaemonControllerDelegateLinux() { | 146 DaemonControllerDelegateLinux::DaemonControllerDelegateLinux() { |
124 } | 147 } |
125 | 148 |
126 DaemonControllerDelegateLinux::~DaemonControllerDelegateLinux() { | 149 DaemonControllerDelegateLinux::~DaemonControllerDelegateLinux() { |
127 } | 150 } |
128 | 151 |
129 DaemonController::State DaemonControllerDelegateLinux::GetState() { | 152 DaemonController::State DaemonControllerDelegateLinux::GetState() { |
130 base::FilePath script_path; | 153 base::FilePath script_path; |
131 if (!GetScriptPath(&script_path)) { | 154 if (!GetScriptPath(&script_path)) { |
132 LOG(ERROR) << "GetScriptPath() failed."; | 155 LOG(ERROR) << "GetScriptPath() failed"; |
133 return DaemonController::STATE_UNKNOWN; | 156 return DaemonController::STATE_UNKNOWN; |
134 } | 157 } |
135 base::CommandLine command_line(script_path); | 158 base::CommandLine command_line(script_path); |
136 command_line.AppendArg("--get-status"); | 159 command_line.AppendArg("--get-status"); |
137 | 160 |
138 std::string status; | 161 std::string status; |
139 int exit_code = 0; | 162 int exit_code = 0; |
140 if (!base::GetAppOutputWithExitCode(command_line, &status, &exit_code) || | 163 if (!base::GetAppOutputWithExitCode(command_line, &status, &exit_code) || |
141 exit_code != 0) { | 164 exit_code != 0) { |
142 LOG(ERROR) << "Failed to run \"" << command_line.GetCommandLineString() | 165 LOG(ERROR) << "Failed to run \"" << command_line.GetCommandLineString() |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 } | 198 } |
176 if (config->GetString(kXmppLoginConfigPath, &value)) { | 199 if (config->GetString(kXmppLoginConfigPath, &value)) { |
177 result->SetString(kXmppLoginConfigPath, value); | 200 result->SetString(kXmppLoginConfigPath, value); |
178 } | 201 } |
179 return result.Pass(); | 202 return result.Pass(); |
180 } | 203 } |
181 | 204 |
182 void DaemonControllerDelegateLinux::SetConfigAndStart( | 205 void DaemonControllerDelegateLinux::SetConfigAndStart( |
183 scoped_ptr<base::DictionaryValue> config, | 206 scoped_ptr<base::DictionaryValue> config, |
184 bool consent, | 207 bool consent, |
185 const DaemonController::CompletionCallback& done) { | 208 const base::Closure& on_done, |
| 209 const DaemonController::ErrorCallback& on_error) { |
186 // Add the user to chrome-remote-desktop group first. | 210 // Add the user to chrome-remote-desktop group first. |
187 std::vector<std::string> args; | 211 std::vector<std::string> args; |
188 args.push_back("--add-user"); | 212 args.push_back("--add-user"); |
189 int exit_code; | |
190 if (!RunHostScriptWithTimeout( | 213 if (!RunHostScriptWithTimeout( |
191 args, base::TimeDelta::FromSeconds(kSudoTimeoutSeconds), | 214 args, base::TimeDelta::FromSeconds(kSudoTimeoutSeconds), |
192 &exit_code) || | 215 on_error)) { |
193 exit_code != 0) { | |
194 LOG(ERROR) << "Failed to add user to chrome-remote-desktop group."; | |
195 done.Run(DaemonController::RESULT_FAILED); | |
196 return; | 216 return; |
197 } | 217 } |
198 | 218 |
199 // Ensure the configuration directory exists. | 219 // Ensure the configuration directory exists. |
200 base::FilePath config_dir = GetConfigPath().DirName(); | 220 base::FilePath config_dir = GetConfigPath().DirName(); |
201 if (!base::DirectoryExists(config_dir) && | 221 if (!base::DirectoryExists(config_dir) && |
202 !base::CreateDirectory(config_dir)) { | 222 !base::CreateDirectory(config_dir)) { |
203 LOG(ERROR) << "Failed to create config directory " << config_dir.value(); | 223 std::ostringstream error_message; |
204 done.Run(DaemonController::RESULT_FAILED); | 224 error_message << "Failed to create config directory " << config_dir.value(); |
| 225 LOG(ERROR) << error_message; |
| 226 on_error.Run(error_message.str(), FROM_HERE); |
205 return; | 227 return; |
206 } | 228 } |
207 | 229 |
208 // Write config. | 230 // Write config. |
209 if (!HostConfigToJsonFile(*config, GetConfigPath())) { | 231 if (!HostConfigToJsonFile(*config, GetConfigPath())) { |
210 LOG(ERROR) << "Failed to update config file."; | 232 std::string error_message = "Failed to update config file"; |
211 done.Run(DaemonController::RESULT_FAILED); | 233 LOG(ERROR) << error_message; |
| 234 on_error.Run(error_message, FROM_HERE); |
212 return; | 235 return; |
213 } | 236 } |
214 | 237 |
215 // Finally start the host. | 238 // Finally start the host. |
216 args.clear(); | 239 args.clear(); |
217 args.push_back("--start"); | 240 args.push_back("--start"); |
218 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 241 if (RunHostScript(args, on_error)) { |
219 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 242 on_done.Run(); |
220 result = DaemonController::RESULT_OK; | 243 } |
221 | |
222 done.Run(result); | |
223 } | 244 } |
224 | 245 |
225 void DaemonControllerDelegateLinux::UpdateConfig( | 246 void DaemonControllerDelegateLinux::UpdateConfig( |
226 scoped_ptr<base::DictionaryValue> config, | 247 scoped_ptr<base::DictionaryValue> config, |
227 const DaemonController::CompletionCallback& done) { | 248 const base::Closure& on_done, |
| 249 const DaemonController::ErrorCallback& on_error) { |
228 scoped_ptr<base::DictionaryValue> new_config( | 250 scoped_ptr<base::DictionaryValue> new_config( |
229 HostConfigFromJsonFile(GetConfigPath())); | 251 HostConfigFromJsonFile(GetConfigPath())); |
230 if (new_config) | 252 if (!new_config) { |
231 new_config->MergeDictionary(config.get()); | 253 std::ostringstream error_message; |
232 if (!new_config || !HostConfigToJsonFile(*new_config, GetConfigPath())) { | 254 error_message << "Reading config from " << GetConfigPath().value() |
233 LOG(ERROR) << "Failed to update config file."; | 255 << " failed"; |
234 done.Run(DaemonController::RESULT_FAILED); | 256 LOG(ERROR) << error_message; |
| 257 on_error.Run(error_message.str(), FROM_HERE); |
| 258 return; |
| 259 } |
| 260 |
| 261 new_config->MergeDictionary(config.get()); |
| 262 if (!HostConfigToJsonFile(*new_config, GetConfigPath())) { |
| 263 std::ostringstream error_message; |
| 264 error_message << "Writing config to " << GetConfigPath().value() |
| 265 << " failed"; |
| 266 LOG(ERROR) << error_message; |
| 267 on_error.Run(error_message.str(), FROM_HERE); |
235 return; | 268 return; |
236 } | 269 } |
237 | 270 |
238 std::vector<std::string> args; | 271 std::vector<std::string> args; |
239 args.push_back("--reload"); | 272 args.push_back("--reload"); |
240 int exit_code = 0; | 273 if (RunHostScript(args, on_error)) { |
241 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 274 on_done.Run(); |
242 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 275 } |
243 result = DaemonController::RESULT_OK; | |
244 | |
245 done.Run(result); | |
246 } | 276 } |
247 | 277 |
248 void DaemonControllerDelegateLinux::Stop( | 278 void DaemonControllerDelegateLinux::Stop( |
249 const DaemonController::CompletionCallback& done) { | 279 const base::Closure& on_done, |
| 280 const DaemonController::ErrorCallback& on_error) { |
250 std::vector<std::string> args; | 281 std::vector<std::string> args; |
251 args.push_back("--stop"); | 282 args.push_back("--stop"); |
252 int exit_code = 0; | 283 if (RunHostScript(args, on_error)) { |
253 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 284 on_done.Run(); |
254 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 285 } |
255 result = DaemonController::RESULT_OK; | |
256 | |
257 done.Run(result); | |
258 } | 286 } |
259 | 287 |
260 DaemonController::UsageStatsConsent | 288 DaemonController::UsageStatsConsent |
261 DaemonControllerDelegateLinux::GetUsageStatsConsent() { | 289 DaemonControllerDelegateLinux::GetUsageStatsConsent() { |
262 // Crash dump collection is not implemented on Linux yet. | 290 // Crash dump collection is not implemented on Linux yet. |
263 // http://crbug.com/130678. | 291 // http://crbug.com/130678. |
264 DaemonController::UsageStatsConsent consent; | 292 DaemonController::UsageStatsConsent consent; |
265 consent.supported = false; | 293 consent.supported = false; |
266 consent.allowed = false; | 294 consent.allowed = false; |
267 consent.set_by_policy = false; | 295 consent.set_by_policy = false; |
268 return consent; | 296 return consent; |
269 } | 297 } |
270 | 298 |
271 scoped_refptr<DaemonController> DaemonController::Create() { | 299 scoped_refptr<DaemonController> DaemonController::Create() { |
272 scoped_ptr<DaemonController::Delegate> delegate( | 300 scoped_ptr<DaemonController::Delegate> delegate( |
273 new DaemonControllerDelegateLinux()); | 301 new DaemonControllerDelegateLinux()); |
274 return new DaemonController(delegate.Pass()); | 302 return new DaemonController(delegate.Pass()); |
275 } | 303 } |
276 | 304 |
277 } // namespace remoting | 305 } // namespace remoting |
OLD | NEW |