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