SBPlatform.cpp revision 344779
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
26using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------
30// PlatformConnectOptions
31//----------------------------------------------------------------------
32struct 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//----------------------------------------------------------------------
54struct 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//----------------------------------------------------------------------
73SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url)
74    : m_opaque_ptr(new PlatformConnectOptions(url)) {}
75
76SBPlatformConnectOptions::SBPlatformConnectOptions(
77    const SBPlatformConnectOptions &rhs)
78    : m_opaque_ptr(new PlatformConnectOptions()) {
79  *m_opaque_ptr = *rhs.m_opaque_ptr;
80}
81
82SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; }
83
84void SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) {
85  *m_opaque_ptr = *rhs.m_opaque_ptr;
86}
87
88const 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
94void 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
101bool SBPlatformConnectOptions::GetRsyncEnabled() {
102  return m_opaque_ptr->m_rsync_enabled;
103}
104
105void 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
122void SBPlatformConnectOptions::DisableRsync() {
123  m_opaque_ptr->m_rsync_enabled = false;
124}
125
126const char *SBPlatformConnectOptions::GetLocalCacheDirectory() {
127  return m_opaque_ptr->m_local_cache_directory.GetCString();
128}
129
130void 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//----------------------------------------------------------------------
140SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command)
141    : m_opaque_ptr(new PlatformShellCommand(shell_command)) {}
142
143SBPlatformShellCommand::SBPlatformShellCommand(
144    const SBPlatformShellCommand &rhs)
145    : m_opaque_ptr(new PlatformShellCommand()) {
146  *m_opaque_ptr = *rhs.m_opaque_ptr;
147}
148
149SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; }
150
151void 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
157const 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
163void 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
170const 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
176void 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
183uint32_t SBPlatformShellCommand::GetTimeoutSeconds() {
184  if (m_opaque_ptr->m_timeout)
185    return m_opaque_ptr->m_timeout->count();
186  return UINT32_MAX;
187}
188
189void 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
196int SBPlatformShellCommand::GetSignal() { return m_opaque_ptr->m_signo; }
197
198int SBPlatformShellCommand::GetStatus() { return m_opaque_ptr->m_status; }
199
200const 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//----------------------------------------------------------------------
209SBPlatform::SBPlatform() : m_opaque_sp() {}
210
211SBPlatform::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
217SBPlatform::~SBPlatform() {}
218
219bool SBPlatform::IsValid() const { return m_opaque_sp.get() != NULL; }
220
221void SBPlatform::Clear() { m_opaque_sp.reset(); }
222
223const char *SBPlatform::GetName() {
224  PlatformSP platform_sp(GetSP());
225  if (platform_sp)
226    return platform_sp->GetName().GetCString();
227  return NULL;
228}
229
230lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; }
231
232void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) {
233  m_opaque_sp = platform_sp;
234}
235
236const char *SBPlatform::GetWorkingDirectory() {
237  PlatformSP platform_sp(GetSP());
238  if (platform_sp)
239    return platform_sp->GetWorkingDirectory().GetCString();
240  return NULL;
241}
242
243bool SBPlatform::SetWorkingDirectory(const char *path) {
244  PlatformSP platform_sp(GetSP());
245  if (platform_sp) {
246    if (path)
247      platform_sp->SetWorkingDirectory(FileSpec(path));
248    else
249      platform_sp->SetWorkingDirectory(FileSpec());
250    return true;
251  }
252  return false;
253}
254
255SBError 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
269void SBPlatform::DisconnectRemote() {
270  PlatformSP platform_sp(GetSP());
271  if (platform_sp)
272    platform_sp->DisconnectRemote();
273}
274
275bool SBPlatform::IsConnected() {
276  PlatformSP platform_sp(GetSP());
277  if (platform_sp)
278    return platform_sp->IsConnected();
279  return false;
280}
281
282const 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
295const 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
310const 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
325const char *SBPlatform::GetHostname() {
326  PlatformSP platform_sp(GetSP());
327  if (platform_sp)
328    return platform_sp->GetHostname();
329  return NULL;
330}
331
332uint32_t SBPlatform::GetOSMajorVersion() {
333  llvm::VersionTuple version;
334  if (PlatformSP platform_sp = GetSP())
335    version = platform_sp->GetOSVersion();
336  return version.empty() ? UINT32_MAX : version.getMajor();
337}
338
339uint32_t SBPlatform::GetOSMinorVersion() {
340  llvm::VersionTuple version;
341  if (PlatformSP platform_sp = GetSP())
342    version = platform_sp->GetOSVersion();
343  return version.getMinor().getValueOr(UINT32_MAX);
344}
345
346uint32_t SBPlatform::GetOSUpdateVersion() {
347  llvm::VersionTuple version;
348  if (PlatformSP platform_sp = GetSP())
349    version = platform_sp->GetOSVersion();
350  return version.getSubminor().getValueOr(UINT32_MAX);
351}
352
353SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) {
354  SBError sb_error;
355  PlatformSP platform_sp(GetSP());
356  if (platform_sp) {
357    sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref());
358  } else {
359    sb_error.SetErrorString("invalid platform");
360  }
361  return sb_error;
362}
363
364SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
365  return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
366    if (src.Exists()) {
367      uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref());
368      if (permissions == 0) {
369        if (FileSystem::Instance().IsDirectory(src.ref()))
370          permissions = eFilePermissionsDirectoryDefault;
371        else
372          permissions = eFilePermissionsFileDefault;
373      }
374
375      return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
376    }
377
378    Status error;
379    error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
380                                   src.ref().GetPath().c_str());
381    return error;
382  });
383}
384
385SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
386  return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
387    if (src.Exists())
388      return platform_sp->Install(src.ref(), dst.ref());
389
390    Status error;
391    error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
392                                   src.ref().GetPath().c_str());
393    return error;
394  });
395}
396
397SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
398  return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
399    const char *command = shell_command.GetCommand();
400    if (!command)
401      return Status("invalid shell command (empty)");
402
403    const char *working_dir = shell_command.GetWorkingDirectory();
404    if (working_dir == NULL) {
405      working_dir = platform_sp->GetWorkingDirectory().GetCString();
406      if (working_dir)
407        shell_command.SetWorkingDirectory(working_dir);
408    }
409    return platform_sp->RunShellCommand(command, FileSpec(working_dir),
410                                        &shell_command.m_opaque_ptr->m_status,
411                                        &shell_command.m_opaque_ptr->m_signo,
412                                        &shell_command.m_opaque_ptr->m_output,
413                                        shell_command.m_opaque_ptr->m_timeout);
414  });
415}
416
417SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
418  return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
419    ProcessLaunchInfo info = launch_info.ref();
420    Status error = platform_sp->LaunchProcess(info);
421    launch_info.set_ref(info);
422    return error;
423  });
424}
425
426SBError SBPlatform::Kill(const lldb::pid_t pid) {
427  return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
428    return platform_sp->KillProcess(pid);
429  });
430}
431
432SBError SBPlatform::ExecuteConnected(
433    const std::function<Status(const lldb::PlatformSP &)> &func) {
434  SBError sb_error;
435  const auto platform_sp(GetSP());
436  if (platform_sp) {
437    if (platform_sp->IsConnected())
438      sb_error.ref() = func(platform_sp);
439    else
440      sb_error.SetErrorString("not connected");
441  } else
442    sb_error.SetErrorString("invalid platform");
443
444  return sb_error;
445}
446
447SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) {
448  SBError sb_error;
449  PlatformSP platform_sp(GetSP());
450  if (platform_sp) {
451    sb_error.ref() =
452        platform_sp->MakeDirectory(FileSpec(path), file_permissions);
453  } else {
454    sb_error.SetErrorString("invalid platform");
455  }
456  return sb_error;
457}
458
459uint32_t SBPlatform::GetFilePermissions(const char *path) {
460  PlatformSP platform_sp(GetSP());
461  if (platform_sp) {
462    uint32_t file_permissions = 0;
463    platform_sp->GetFilePermissions(FileSpec(path), file_permissions);
464    return file_permissions;
465  }
466  return 0;
467}
468
469SBError SBPlatform::SetFilePermissions(const char *path,
470                                       uint32_t file_permissions) {
471  SBError sb_error;
472  PlatformSP platform_sp(GetSP());
473  if (platform_sp) {
474    sb_error.ref() =
475        platform_sp->SetFilePermissions(FileSpec(path), file_permissions);
476  } else {
477    sb_error.SetErrorString("invalid platform");
478  }
479  return sb_error;
480}
481
482SBUnixSignals SBPlatform::GetUnixSignals() const {
483  if (auto platform_sp = GetSP())
484    return SBUnixSignals{platform_sp};
485
486  return {};
487}
488