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/Target.h"
20 #include "lldb/Target/Platform.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(),
33         m_rsync_options(),
34         m_rsync_remote_path_prefix(),
35         m_rsync_enabled(false),
36         m_rsync_omit_hostname_from_remote_path(false),
37         m_local_cache_directory ()
38     {
39         if (url && url[0])
40             m_url = url;
41     }
42 
43     ~PlatformConnectOptions()
44     {
45     }
46 
47     std::string m_url;
48     std::string m_rsync_options;
49     std::string m_rsync_remote_path_prefix;
50     bool m_rsync_enabled;
51     bool m_rsync_omit_hostname_from_remote_path;
52     ConstString m_local_cache_directory;
53 };
54 
55 //----------------------------------------------------------------------
56 // PlatformShellCommand
57 //----------------------------------------------------------------------
58 struct PlatformShellCommand {
59     PlatformShellCommand(const char *shell_command = NULL) :
60         m_command(),
61         m_working_dir(),
62         m_status(0),
63         m_signo(0),
64         m_timeout_sec(UINT32_MAX)
65     {
66         if (shell_command && shell_command[0])
67             m_command = shell_command;
68     }
69 
70     ~PlatformShellCommand()
71     {
72     }
73 
74     std::string m_command;
75     std::string m_working_dir;
76     std::string m_output;
77     int m_status;
78     int m_signo;
79     uint32_t m_timeout_sec;
80 };
81 //----------------------------------------------------------------------
82 // SBPlatformConnectOptions
83 //----------------------------------------------------------------------
84 SBPlatformConnectOptions::SBPlatformConnectOptions (const char *url) :
85     m_opaque_ptr(new PlatformConnectOptions(url))
86 {
87 
88 }
89 
90 SBPlatformConnectOptions::SBPlatformConnectOptions(const SBPlatformConnectOptions &rhs) :
91     m_opaque_ptr(new PlatformConnectOptions())
92 {
93     *m_opaque_ptr = *rhs.m_opaque_ptr;
94 }
95 
96 SBPlatformConnectOptions::~SBPlatformConnectOptions ()
97 {
98     delete m_opaque_ptr;
99 }
100 
101 void
102 SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs)
103 {
104     *m_opaque_ptr = *rhs.m_opaque_ptr;
105 }
106 
107 const char *
108 SBPlatformConnectOptions::GetURL()
109 {
110     if (m_opaque_ptr->m_url.empty())
111         return NULL;
112     return m_opaque_ptr->m_url.c_str();
113 }
114 
115 void
116 SBPlatformConnectOptions::SetURL(const char *url)
117 {
118     if (url && url[0])
119         m_opaque_ptr->m_url = url;
120     else
121         m_opaque_ptr->m_url.clear();
122 }
123 
124 bool
125 SBPlatformConnectOptions::GetRsyncEnabled()
126 {
127     return m_opaque_ptr->m_rsync_enabled;
128 }
129 
130 void
131 SBPlatformConnectOptions::EnableRsync (const char *options,
132                                        const char *remote_path_prefix,
133                                        bool omit_hostname_from_remote_path)
134 {
135     m_opaque_ptr->m_rsync_enabled = true;
136     m_opaque_ptr->m_rsync_omit_hostname_from_remote_path = omit_hostname_from_remote_path;
137     if (remote_path_prefix && remote_path_prefix[0])
138         m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix;
139     else
140         m_opaque_ptr->m_rsync_remote_path_prefix.clear();
141 
142     if (options && options[0])
143         m_opaque_ptr->m_rsync_options = options;
144     else
145         m_opaque_ptr->m_rsync_options.clear();
146 
147 }
148 
149 void
150 SBPlatformConnectOptions::DisableRsync ()
151 {
152     m_opaque_ptr->m_rsync_enabled = false;
153 }
154 
155 const char *
156 SBPlatformConnectOptions::GetLocalCacheDirectory()
157 {
158     return m_opaque_ptr->m_local_cache_directory.GetCString();
159 }
160 
161 void
162 SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path)
163 {
164     if (path && path[0])
165         m_opaque_ptr->m_local_cache_directory.SetCString(path);
166     else
167         m_opaque_ptr->m_local_cache_directory = ConstString();
168 }
169 
170 //----------------------------------------------------------------------
171 // SBPlatformShellCommand
172 //----------------------------------------------------------------------
173 SBPlatformShellCommand::SBPlatformShellCommand (const char *shell_command) :
174     m_opaque_ptr(new PlatformShellCommand(shell_command))
175 {
176 }
177 
178 SBPlatformShellCommand::SBPlatformShellCommand (const SBPlatformShellCommand &rhs) :
179     m_opaque_ptr(new PlatformShellCommand())
180 {
181     *m_opaque_ptr = *rhs.m_opaque_ptr;
182 }
183 
184 SBPlatformShellCommand::~SBPlatformShellCommand()
185 {
186     delete m_opaque_ptr;
187 }
188 
189 void
190 SBPlatformShellCommand::Clear()
191 {
192     m_opaque_ptr->m_output = std::move(std::string());
193     m_opaque_ptr->m_status = 0;
194     m_opaque_ptr->m_signo = 0;
195 }
196 
197 const char *
198 SBPlatformShellCommand::GetCommand()
199 {
200     if (m_opaque_ptr->m_command.empty())
201         return NULL;
202     return m_opaque_ptr->m_command.c_str();
203 }
204 
205 void
206 SBPlatformShellCommand::SetCommand(const char *shell_command)
207 {
208     if (shell_command && shell_command[0])
209         m_opaque_ptr->m_command = shell_command;
210     else
211         m_opaque_ptr->m_command.clear();
212 }
213 
214 const char *
215 SBPlatformShellCommand::GetWorkingDirectory ()
216 {
217     if (m_opaque_ptr->m_working_dir.empty())
218         return NULL;
219     return m_opaque_ptr->m_working_dir.c_str();
220 }
221 
222 void
223 SBPlatformShellCommand::SetWorkingDirectory (const char *path)
224 {
225     if (path && path[0])
226         m_opaque_ptr->m_working_dir = path;
227     else
228         m_opaque_ptr->m_working_dir.clear();
229 }
230 
231 uint32_t
232 SBPlatformShellCommand::GetTimeoutSeconds ()
233 {
234     return m_opaque_ptr->m_timeout_sec;
235 }
236 
237 void
238 SBPlatformShellCommand::SetTimeoutSeconds (uint32_t sec)
239 {
240     m_opaque_ptr->m_timeout_sec = sec;
241 }
242 
243 int
244 SBPlatformShellCommand::GetSignal ()
245 {
246     return m_opaque_ptr->m_signo;
247 }
248 
249 int
250 SBPlatformShellCommand::GetStatus ()
251 {
252     return m_opaque_ptr->m_status;
253 }
254 
255 const char *
256 SBPlatformShellCommand::GetOutput ()
257 {
258     if (m_opaque_ptr->m_output.empty())
259         return NULL;
260     return m_opaque_ptr->m_output.c_str();
261 }
262 
263 //----------------------------------------------------------------------
264 // SBPlatform
265 //----------------------------------------------------------------------
266 SBPlatform::SBPlatform () :
267     m_opaque_sp ()
268 {
269 
270 }
271 
272 SBPlatform::SBPlatform (const char *platform_name) :
273     m_opaque_sp ()
274 {
275     Error error;
276     if (platform_name && platform_name[0])
277         m_opaque_sp = Platform::Create (ConstString(platform_name), error);
278 }
279 
280 SBPlatform::~SBPlatform()
281 {
282 }
283 
284 bool
285 SBPlatform::IsValid () const
286 {
287     return m_opaque_sp.get() != NULL;
288 }
289 
290 void
291 SBPlatform::Clear ()
292 {
293     m_opaque_sp.reset();
294 }
295 
296 const char *
297 SBPlatform::GetName ()
298 {
299     PlatformSP platform_sp(GetSP());
300     if (platform_sp)
301         return platform_sp->GetName().GetCString();
302     return NULL;
303 }
304 
305 lldb::PlatformSP
306 SBPlatform::GetSP () const
307 {
308     return m_opaque_sp;
309 }
310 
311 void
312 SBPlatform::SetSP (const lldb::PlatformSP& platform_sp)
313 {
314     m_opaque_sp = platform_sp;
315 }
316 
317 const char *
318 SBPlatform::GetWorkingDirectory()
319 {
320     PlatformSP platform_sp(GetSP());
321     if (platform_sp)
322         return platform_sp->GetWorkingDirectory().GetCString();
323     return NULL;
324 }
325 
326 bool
327 SBPlatform::SetWorkingDirectory(const char *path)
328 {
329     PlatformSP platform_sp(GetSP());
330     if (platform_sp)
331     {
332         if (path)
333             platform_sp->SetWorkingDirectory(FileSpec{path, false});
334         else
335             platform_sp->SetWorkingDirectory(FileSpec{});
336         return true;
337     }
338     return false;
339 }
340 
341 SBError
342 SBPlatform::ConnectRemote (SBPlatformConnectOptions &connect_options)
343 {
344     SBError sb_error;
345     PlatformSP platform_sp(GetSP());
346     if (platform_sp && connect_options.GetURL())
347     {
348         Args args;
349         args.AppendArgument(connect_options.GetURL());
350         sb_error.ref() = platform_sp->ConnectRemote(args);
351     }
352     else
353     {
354         sb_error.SetErrorString("invalid platform");
355     }
356     return sb_error;
357 }
358 
359 void
360 SBPlatform::DisconnectRemote ()
361 {
362     PlatformSP platform_sp(GetSP());
363     if (platform_sp)
364         platform_sp->DisconnectRemote();
365 }
366 
367 bool
368 SBPlatform::IsConnected()
369 {
370     PlatformSP platform_sp(GetSP());
371     if (platform_sp)
372         platform_sp->IsConnected();
373     return false;
374 }
375 
376 const char *
377 SBPlatform::GetTriple()
378 {
379     PlatformSP platform_sp(GetSP());
380     if (platform_sp)
381     {
382         ArchSpec arch(platform_sp->GetSystemArchitecture());
383         if (arch.IsValid())
384         {
385             // Const-ify the string so we don't need to worry about the lifetime of the string
386             return ConstString(arch.GetTriple().getTriple().c_str()).GetCString();
387         }
388     }
389     return NULL;
390 }
391 
392 const char *
393 SBPlatform::GetOSBuild()
394 {
395     PlatformSP platform_sp(GetSP());
396     if (platform_sp)
397     {
398         std::string s;
399         if (platform_sp->GetOSBuildString(s))
400         {
401             if (!s.empty())
402             {
403                 // Const-ify the string so we don't need to worry about the lifetime of the string
404                 return ConstString(s.c_str()).GetCString();
405             }
406         }
407     }
408     return NULL;
409 }
410 
411 const char *
412 SBPlatform::GetOSDescription()
413 {
414     PlatformSP platform_sp(GetSP());
415     if (platform_sp)
416     {
417         std::string s;
418         if (platform_sp->GetOSKernelDescription(s))
419         {
420             if (!s.empty())
421             {
422                 // Const-ify the string so we don't need to worry about the lifetime of the string
423                 return ConstString(s.c_str()).GetCString();
424             }
425         }
426     }
427     return NULL;
428 }
429 
430 const char *
431 SBPlatform::GetHostname ()
432 {
433     PlatformSP platform_sp(GetSP());
434     if (platform_sp)
435         return platform_sp->GetHostname();
436     return NULL;
437 }
438 
439 uint32_t
440 SBPlatform::GetOSMajorVersion ()
441 {
442     uint32_t major, minor, update;
443     PlatformSP platform_sp(GetSP());
444     if (platform_sp && platform_sp->GetOSVersion(major, minor, update))
445         return major;
446     return UINT32_MAX;
447 
448 }
449 
450 uint32_t
451 SBPlatform::GetOSMinorVersion ()
452 {
453     uint32_t major, minor, update;
454     PlatformSP platform_sp(GetSP());
455     if (platform_sp && platform_sp->GetOSVersion(major, minor, update))
456         return minor;
457     return UINT32_MAX;
458 }
459 
460 uint32_t
461 SBPlatform::GetOSUpdateVersion ()
462 {
463     uint32_t major, minor, update;
464     PlatformSP platform_sp(GetSP());
465     if (platform_sp && platform_sp->GetOSVersion(major, minor, update))
466         return update;
467     return UINT32_MAX;
468 }
469 
470 SBError
471 SBPlatform::Get (SBFileSpec &src,
472                  SBFileSpec &dst)
473 {
474     SBError sb_error;
475     PlatformSP platform_sp(GetSP());
476     if (platform_sp)
477     {
478         sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref());
479     }
480     else
481     {
482         sb_error.SetErrorString("invalid platform");
483     }
484     return sb_error;
485 }
486 
487 SBError
488 SBPlatform::Put (SBFileSpec &src,
489                  SBFileSpec &dst)
490 {
491   return ExecuteConnected(
492       [&](const lldb::PlatformSP& platform_sp)
493       {
494           if (src.Exists())
495           {
496               uint32_t permissions = src.ref().GetPermissions();
497               if (permissions == 0)
498               {
499                   if (src.ref().GetFileType() == FileSpec::eFileTypeDirectory)
500                       permissions = eFilePermissionsDirectoryDefault;
501                   else
502                       permissions = eFilePermissionsFileDefault;
503               }
504 
505               return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
506           }
507 
508           Error error;
509           error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str());
510           return error;
511       });
512 }
513 
514 SBError
515 SBPlatform::Install (SBFileSpec &src,
516                      SBFileSpec &dst)
517 {
518   return ExecuteConnected(
519       [&](const lldb::PlatformSP& platform_sp)
520       {
521           if (src.Exists())
522               return platform_sp->Install(src.ref(), dst.ref());
523 
524           Error error;
525           error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str());
526           return error;
527       });
528 }
529 
530 
531 SBError
532 SBPlatform::Run (SBPlatformShellCommand &shell_command)
533 {
534     return ExecuteConnected(
535         [&](const lldb::PlatformSP& platform_sp)
536         {
537             const char *command = shell_command.GetCommand();
538             if (!command)
539                 return Error("invalid shell command (empty)");
540 
541             const char *working_dir = shell_command.GetWorkingDirectory();
542             if (working_dir == NULL)
543             {
544                 working_dir = platform_sp->GetWorkingDirectory().GetCString();
545                 if (working_dir)
546                     shell_command.SetWorkingDirectory(working_dir);
547             }
548             return platform_sp->RunShellCommand(command,
549                                                 FileSpec{working_dir, false},
550                                                 &shell_command.m_opaque_ptr->m_status,
551                                                 &shell_command.m_opaque_ptr->m_signo,
552                                                 &shell_command.m_opaque_ptr->m_output,
553                                                 shell_command.m_opaque_ptr->m_timeout_sec);
554         });
555 }
556 
557 SBError
558 SBPlatform::Launch (SBLaunchInfo &launch_info)
559 {
560     return ExecuteConnected(
561         [&](const lldb::PlatformSP& platform_sp)
562         {
563             return platform_sp->LaunchProcess(launch_info.ref());
564         });
565 }
566 
567 SBError
568 SBPlatform::Kill (const lldb::pid_t pid)
569 {
570     return ExecuteConnected(
571         [&](const lldb::PlatformSP& platform_sp)
572         {
573             return platform_sp->KillProcess(pid);
574         });
575 }
576 
577 SBError
578 SBPlatform::ExecuteConnected (const std::function<Error(const lldb::PlatformSP&)>& func)
579 {
580     SBError sb_error;
581     const auto platform_sp(GetSP());
582     if (platform_sp)
583     {
584         if (platform_sp->IsConnected())
585             sb_error.ref() = func(platform_sp);
586         else
587             sb_error.SetErrorString("not connected");
588     }
589     else
590         sb_error.SetErrorString("invalid platform");
591 
592   return sb_error;
593 }
594 
595 SBError
596 SBPlatform::MakeDirectory (const char *path, uint32_t file_permissions)
597 {
598     SBError sb_error;
599     PlatformSP platform_sp(GetSP());
600     if (platform_sp)
601     {
602         sb_error.ref() = platform_sp->MakeDirectory(FileSpec{path, false}, file_permissions);
603     }
604     else
605     {
606         sb_error.SetErrorString("invalid platform");
607     }
608     return sb_error;
609 }
610 
611 uint32_t
612 SBPlatform::GetFilePermissions (const char *path)
613 {
614     PlatformSP platform_sp(GetSP());
615     if (platform_sp)
616     {
617         uint32_t file_permissions = 0;
618         platform_sp->GetFilePermissions(FileSpec{path, false}, file_permissions);
619         return file_permissions;
620     }
621     return 0;
622 
623 }
624 
625 SBError
626 SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions)
627 {
628     SBError sb_error;
629     PlatformSP platform_sp(GetSP());
630     if (platform_sp)
631     {
632         sb_error.ref() = platform_sp->SetFilePermissions(FileSpec{path, false}, file_permissions);
633     }
634     else
635     {
636         sb_error.SetErrorString("invalid platform");
637     }
638     return sb_error;
639 
640 }
641 
642 SBUnixSignals
643 SBPlatform::GetUnixSignals() const
644 {
645     if (auto platform_sp = GetSP())
646         return SBUnixSignals{platform_sp};
647 
648     return {};
649 }
650