1 //===-- SBPlatform.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/API/SBPlatform.h"
11 #include "lldb/API/SBError.h"
12 #include "lldb/API/SBFileSpec.h"
13 #include "lldb/API/SBLaunchInfo.h"
14 #include "lldb/API/SBUnixSignals.h"
15 #include "lldb/Core/ArchSpec.h"
16 #include "lldb/Core/Error.h"
17 #include "lldb/Host/File.h"
18 #include "lldb/Interpreter/Args.h"
19 #include "lldb/Target/Platform.h"
20 #include "lldb/Target/Target.h"
21 
22 #include <functional>
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 //----------------------------------------------------------------------
28 // PlatformConnectOptions
29 //----------------------------------------------------------------------
30 struct PlatformConnectOptions {
31   PlatformConnectOptions(const char *url = NULL)
32       : m_url(), m_rsync_options(), m_rsync_remote_path_prefix(),
33         m_rsync_enabled(false), m_rsync_omit_hostname_from_remote_path(false),
34         m_local_cache_directory() {
35     if (url && url[0])
36       m_url = url;
37   }
38 
39   ~PlatformConnectOptions() {}
40 
41   std::string m_url;
42   std::string m_rsync_options;
43   std::string m_rsync_remote_path_prefix;
44   bool m_rsync_enabled;
45   bool m_rsync_omit_hostname_from_remote_path;
46   ConstString m_local_cache_directory;
47 };
48 
49 //----------------------------------------------------------------------
50 // PlatformShellCommand
51 //----------------------------------------------------------------------
52 struct PlatformShellCommand {
53   PlatformShellCommand(const char *shell_command = NULL)
54       : m_command(), m_working_dir(), m_status(0), m_signo(0),
55         m_timeout_sec(UINT32_MAX) {
56     if (shell_command && shell_command[0])
57       m_command = shell_command;
58   }
59 
60   ~PlatformShellCommand() {}
61 
62   std::string m_command;
63   std::string m_working_dir;
64   std::string m_output;
65   int m_status;
66   int m_signo;
67   uint32_t m_timeout_sec;
68 };
69 //----------------------------------------------------------------------
70 // SBPlatformConnectOptions
71 //----------------------------------------------------------------------
72 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url)
73     : m_opaque_ptr(new PlatformConnectOptions(url)) {}
74 
75 SBPlatformConnectOptions::SBPlatformConnectOptions(
76     const SBPlatformConnectOptions &rhs)
77     : m_opaque_ptr(new PlatformConnectOptions()) {
78   *m_opaque_ptr = *rhs.m_opaque_ptr;
79 }
80 
81 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; }
82 
83 void SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) {
84   *m_opaque_ptr = *rhs.m_opaque_ptr;
85 }
86 
87 const char *SBPlatformConnectOptions::GetURL() {
88   if (m_opaque_ptr->m_url.empty())
89     return NULL;
90   return m_opaque_ptr->m_url.c_str();
91 }
92 
93 void SBPlatformConnectOptions::SetURL(const char *url) {
94   if (url && url[0])
95     m_opaque_ptr->m_url = url;
96   else
97     m_opaque_ptr->m_url.clear();
98 }
99 
100 bool SBPlatformConnectOptions::GetRsyncEnabled() {
101   return m_opaque_ptr->m_rsync_enabled;
102 }
103 
104 void SBPlatformConnectOptions::EnableRsync(
105     const char *options, const char *remote_path_prefix,
106     bool omit_hostname_from_remote_path) {
107   m_opaque_ptr->m_rsync_enabled = true;
108   m_opaque_ptr->m_rsync_omit_hostname_from_remote_path =
109       omit_hostname_from_remote_path;
110   if (remote_path_prefix && remote_path_prefix[0])
111     m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix;
112   else
113     m_opaque_ptr->m_rsync_remote_path_prefix.clear();
114 
115   if (options && options[0])
116     m_opaque_ptr->m_rsync_options = options;
117   else
118     m_opaque_ptr->m_rsync_options.clear();
119 }
120 
121 void SBPlatformConnectOptions::DisableRsync() {
122   m_opaque_ptr->m_rsync_enabled = false;
123 }
124 
125 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() {
126   return m_opaque_ptr->m_local_cache_directory.GetCString();
127 }
128 
129 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) {
130   if (path && path[0])
131     m_opaque_ptr->m_local_cache_directory.SetCString(path);
132   else
133     m_opaque_ptr->m_local_cache_directory = ConstString();
134 }
135 
136 //----------------------------------------------------------------------
137 // SBPlatformShellCommand
138 //----------------------------------------------------------------------
139 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command)
140     : m_opaque_ptr(new PlatformShellCommand(shell_command)) {}
141 
142 SBPlatformShellCommand::SBPlatformShellCommand(
143     const SBPlatformShellCommand &rhs)
144     : m_opaque_ptr(new PlatformShellCommand()) {
145   *m_opaque_ptr = *rhs.m_opaque_ptr;
146 }
147 
148 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; }
149 
150 void SBPlatformShellCommand::Clear() {
151   m_opaque_ptr->m_output = std::string();
152   m_opaque_ptr->m_status = 0;
153   m_opaque_ptr->m_signo = 0;
154 }
155 
156 const char *SBPlatformShellCommand::GetCommand() {
157   if (m_opaque_ptr->m_command.empty())
158     return NULL;
159   return m_opaque_ptr->m_command.c_str();
160 }
161 
162 void SBPlatformShellCommand::SetCommand(const char *shell_command) {
163   if (shell_command && shell_command[0])
164     m_opaque_ptr->m_command = shell_command;
165   else
166     m_opaque_ptr->m_command.clear();
167 }
168 
169 const char *SBPlatformShellCommand::GetWorkingDirectory() {
170   if (m_opaque_ptr->m_working_dir.empty())
171     return NULL;
172   return m_opaque_ptr->m_working_dir.c_str();
173 }
174 
175 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) {
176   if (path && path[0])
177     m_opaque_ptr->m_working_dir = path;
178   else
179     m_opaque_ptr->m_working_dir.clear();
180 }
181 
182 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() {
183   return m_opaque_ptr->m_timeout_sec;
184 }
185 
186 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) {
187   m_opaque_ptr->m_timeout_sec = sec;
188 }
189 
190 int SBPlatformShellCommand::GetSignal() { return m_opaque_ptr->m_signo; }
191 
192 int SBPlatformShellCommand::GetStatus() { return m_opaque_ptr->m_status; }
193 
194 const char *SBPlatformShellCommand::GetOutput() {
195   if (m_opaque_ptr->m_output.empty())
196     return NULL;
197   return m_opaque_ptr->m_output.c_str();
198 }
199 
200 //----------------------------------------------------------------------
201 // SBPlatform
202 //----------------------------------------------------------------------
203 SBPlatform::SBPlatform() : m_opaque_sp() {}
204 
205 SBPlatform::SBPlatform(const char *platform_name) : m_opaque_sp() {
206   Error error;
207   if (platform_name && platform_name[0])
208     m_opaque_sp = Platform::Create(ConstString(platform_name), error);
209 }
210 
211 SBPlatform::~SBPlatform() {}
212 
213 bool SBPlatform::IsValid() const { return m_opaque_sp.get() != NULL; }
214 
215 void SBPlatform::Clear() { m_opaque_sp.reset(); }
216 
217 const char *SBPlatform::GetName() {
218   PlatformSP platform_sp(GetSP());
219   if (platform_sp)
220     return platform_sp->GetName().GetCString();
221   return NULL;
222 }
223 
224 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; }
225 
226 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) {
227   m_opaque_sp = platform_sp;
228 }
229 
230 const char *SBPlatform::GetWorkingDirectory() {
231   PlatformSP platform_sp(GetSP());
232   if (platform_sp)
233     return platform_sp->GetWorkingDirectory().GetCString();
234   return NULL;
235 }
236 
237 bool SBPlatform::SetWorkingDirectory(const char *path) {
238   PlatformSP platform_sp(GetSP());
239   if (platform_sp) {
240     if (path)
241       platform_sp->SetWorkingDirectory(FileSpec{path, false});
242     else
243       platform_sp->SetWorkingDirectory(FileSpec{});
244     return true;
245   }
246   return false;
247 }
248 
249 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) {
250   SBError sb_error;
251   PlatformSP platform_sp(GetSP());
252   if (platform_sp && connect_options.GetURL()) {
253     Args args;
254     args.AppendArgument(connect_options.GetURL());
255     sb_error.ref() = platform_sp->ConnectRemote(args);
256   } else {
257     sb_error.SetErrorString("invalid platform");
258   }
259   return sb_error;
260 }
261 
262 void SBPlatform::DisconnectRemote() {
263   PlatformSP platform_sp(GetSP());
264   if (platform_sp)
265     platform_sp->DisconnectRemote();
266 }
267 
268 bool SBPlatform::IsConnected() {
269   PlatformSP platform_sp(GetSP());
270   if (platform_sp)
271     platform_sp->IsConnected();
272   return false;
273 }
274 
275 const char *SBPlatform::GetTriple() {
276   PlatformSP platform_sp(GetSP());
277   if (platform_sp) {
278     ArchSpec arch(platform_sp->GetSystemArchitecture());
279     if (arch.IsValid()) {
280       // Const-ify the string so we don't need to worry about the lifetime of
281       // the string
282       return ConstString(arch.GetTriple().getTriple().c_str()).GetCString();
283     }
284   }
285   return NULL;
286 }
287 
288 const char *SBPlatform::GetOSBuild() {
289   PlatformSP platform_sp(GetSP());
290   if (platform_sp) {
291     std::string s;
292     if (platform_sp->GetOSBuildString(s)) {
293       if (!s.empty()) {
294         // Const-ify the string so we don't need to worry about the lifetime of
295         // the string
296         return ConstString(s.c_str()).GetCString();
297       }
298     }
299   }
300   return NULL;
301 }
302 
303 const char *SBPlatform::GetOSDescription() {
304   PlatformSP platform_sp(GetSP());
305   if (platform_sp) {
306     std::string s;
307     if (platform_sp->GetOSKernelDescription(s)) {
308       if (!s.empty()) {
309         // Const-ify the string so we don't need to worry about the lifetime of
310         // the string
311         return ConstString(s.c_str()).GetCString();
312       }
313     }
314   }
315   return NULL;
316 }
317 
318 const char *SBPlatform::GetHostname() {
319   PlatformSP platform_sp(GetSP());
320   if (platform_sp)
321     return platform_sp->GetHostname();
322   return NULL;
323 }
324 
325 uint32_t SBPlatform::GetOSMajorVersion() {
326   uint32_t major, minor, update;
327   PlatformSP platform_sp(GetSP());
328   if (platform_sp && platform_sp->GetOSVersion(major, minor, update))
329     return major;
330   return UINT32_MAX;
331 }
332 
333 uint32_t SBPlatform::GetOSMinorVersion() {
334   uint32_t major, minor, update;
335   PlatformSP platform_sp(GetSP());
336   if (platform_sp && platform_sp->GetOSVersion(major, minor, update))
337     return minor;
338   return UINT32_MAX;
339 }
340 
341 uint32_t SBPlatform::GetOSUpdateVersion() {
342   uint32_t major, minor, update;
343   PlatformSP platform_sp(GetSP());
344   if (platform_sp && platform_sp->GetOSVersion(major, minor, update))
345     return update;
346   return UINT32_MAX;
347 }
348 
349 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) {
350   SBError sb_error;
351   PlatformSP platform_sp(GetSP());
352   if (platform_sp) {
353     sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref());
354   } else {
355     sb_error.SetErrorString("invalid platform");
356   }
357   return sb_error;
358 }
359 
360 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
361   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
362     if (src.Exists()) {
363       uint32_t permissions = src.ref().GetPermissions();
364       if (permissions == 0) {
365         if (src.ref().GetFileType() == FileSpec::eFileTypeDirectory)
366           permissions = eFilePermissionsDirectoryDefault;
367         else
368           permissions = eFilePermissionsFileDefault;
369       }
370 
371       return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
372     }
373 
374     Error error;
375     error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
376                                    src.ref().GetPath().c_str());
377     return error;
378   });
379 }
380 
381 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
382   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
383     if (src.Exists())
384       return platform_sp->Install(src.ref(), dst.ref());
385 
386     Error error;
387     error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
388                                    src.ref().GetPath().c_str());
389     return error;
390   });
391 }
392 
393 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
394   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
395     const char *command = shell_command.GetCommand();
396     if (!command)
397       return Error("invalid shell command (empty)");
398 
399     const char *working_dir = shell_command.GetWorkingDirectory();
400     if (working_dir == NULL) {
401       working_dir = platform_sp->GetWorkingDirectory().GetCString();
402       if (working_dir)
403         shell_command.SetWorkingDirectory(working_dir);
404     }
405     return platform_sp->RunShellCommand(
406         command, FileSpec{working_dir, false},
407         &shell_command.m_opaque_ptr->m_status,
408         &shell_command.m_opaque_ptr->m_signo,
409         &shell_command.m_opaque_ptr->m_output,
410         shell_command.m_opaque_ptr->m_timeout_sec);
411   });
412 }
413 
414 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
415   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
416     return platform_sp->LaunchProcess(launch_info.ref());
417   });
418 }
419 
420 SBError SBPlatform::Kill(const lldb::pid_t pid) {
421   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
422     return platform_sp->KillProcess(pid);
423   });
424 }
425 
426 SBError SBPlatform::ExecuteConnected(
427     const std::function<Error(const lldb::PlatformSP &)> &func) {
428   SBError sb_error;
429   const auto platform_sp(GetSP());
430   if (platform_sp) {
431     if (platform_sp->IsConnected())
432       sb_error.ref() = func(platform_sp);
433     else
434       sb_error.SetErrorString("not connected");
435   } else
436     sb_error.SetErrorString("invalid platform");
437 
438   return sb_error;
439 }
440 
441 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) {
442   SBError sb_error;
443   PlatformSP platform_sp(GetSP());
444   if (platform_sp) {
445     sb_error.ref() =
446         platform_sp->MakeDirectory(FileSpec{path, false}, file_permissions);
447   } else {
448     sb_error.SetErrorString("invalid platform");
449   }
450   return sb_error;
451 }
452 
453 uint32_t SBPlatform::GetFilePermissions(const char *path) {
454   PlatformSP platform_sp(GetSP());
455   if (platform_sp) {
456     uint32_t file_permissions = 0;
457     platform_sp->GetFilePermissions(FileSpec{path, false}, file_permissions);
458     return file_permissions;
459   }
460   return 0;
461 }
462 
463 SBError SBPlatform::SetFilePermissions(const char *path,
464                                        uint32_t file_permissions) {
465   SBError sb_error;
466   PlatformSP platform_sp(GetSP());
467   if (platform_sp) {
468     sb_error.ref() = platform_sp->SetFilePermissions(FileSpec{path, false},
469                                                      file_permissions);
470   } else {
471     sb_error.SetErrorString("invalid platform");
472   }
473   return sb_error;
474 }
475 
476 SBUnixSignals SBPlatform::GetUnixSignals() const {
477   if (auto platform_sp = GetSP())
478     return SBUnixSignals{platform_sp};
479 
480   return {};
481 }
482