1 //===-- PlatformPOSIX.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 "PlatformPOSIX.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 
17 #include "lldb/Core/DataBufferHeap.h"
18 #include "lldb/Core/Log.h"
19 #include "lldb/Core/StreamString.h"
20 #include "lldb/Host/File.h"
21 #include "lldb/Host/FileCache.h"
22 #include "lldb/Host/FileSpec.h"
23 #include "lldb/Host/FileSystem.h"
24 #include "lldb/Host/Host.h"
25 #include "lldb/Target/ProcessLaunchInfo.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 
31 //------------------------------------------------------------------
32 /// Default Constructor
33 //------------------------------------------------------------------
34 PlatformPOSIX::PlatformPOSIX (bool is_host) :
35 Platform(is_host),  // This is the local host platform
36 m_remote_platform_sp ()
37 {
38 }
39 
40 //------------------------------------------------------------------
41 /// Destructor.
42 ///
43 /// The destructor is virtual since this class is designed to be
44 /// inherited from by the plug-in instance.
45 //------------------------------------------------------------------
46 PlatformPOSIX::~PlatformPOSIX()
47 {
48 }
49 
50 lldb_private::OptionGroupOptions*
51 PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter)
52 {
53     if (m_options.get() == NULL)
54     {
55         m_options.reset(new OptionGroupOptions(interpreter));
56         m_options->Append(new OptionGroupPlatformRSync());
57         m_options->Append(new OptionGroupPlatformSSH());
58         m_options->Append(new OptionGroupPlatformCaching());
59     }
60     return m_options.get();
61 }
62 
63 bool
64 PlatformPOSIX::IsConnected () const
65 {
66     if (IsHost())
67         return true;
68     else if (m_remote_platform_sp)
69         return m_remote_platform_sp->IsConnected();
70     return false;
71 }
72 
73 lldb_private::Error
74 PlatformPOSIX::RunShellCommand (const char *command,           // Shouldn't be NULL
75                                 const char *working_dir,       // Pass NULL to use the current working directory
76                                 int *status_ptr,               // Pass NULL if you don't want the process exit status
77                                 int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
78                                 std::string *command_output,   // Pass NULL if you don't want the command output
79                                 uint32_t timeout_sec)         // Timeout in seconds to wait for shell program to finish
80 {
81     if (IsHost())
82         return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
83     else
84     {
85         if (m_remote_platform_sp)
86             return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
87         else
88             return Error("unable to run a remote command without a platform");
89     }
90 }
91 
92 Error
93 PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions)
94 {
95     if (m_remote_platform_sp)
96         return m_remote_platform_sp->MakeDirectory(path, file_permissions);
97     else
98         return Platform::MakeDirectory(path ,file_permissions);
99 }
100 
101 Error
102 PlatformPOSIX::GetFilePermissions (const char *path, uint32_t &file_permissions)
103 {
104     if (m_remote_platform_sp)
105         return m_remote_platform_sp->GetFilePermissions(path, file_permissions);
106     else
107         return Platform::GetFilePermissions(path ,file_permissions);
108 }
109 
110 Error
111 PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions)
112 {
113     if (m_remote_platform_sp)
114         return m_remote_platform_sp->SetFilePermissions(path, file_permissions);
115     else
116         return Platform::SetFilePermissions(path ,file_permissions);
117 }
118 
119 lldb::user_id_t
120 PlatformPOSIX::OpenFile (const FileSpec& file_spec,
121                          uint32_t flags,
122                          uint32_t mode,
123                          Error &error)
124 {
125     if (IsHost())
126         return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
127     else if (m_remote_platform_sp)
128         return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
129     else
130         return Platform::OpenFile(file_spec, flags, mode, error);
131 }
132 
133 bool
134 PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error)
135 {
136     if (IsHost())
137         return FileCache::GetInstance().CloseFile(fd, error);
138     else if (m_remote_platform_sp)
139         return m_remote_platform_sp->CloseFile(fd, error);
140     else
141         return Platform::CloseFile(fd, error);
142 }
143 
144 uint64_t
145 PlatformPOSIX::ReadFile (lldb::user_id_t fd,
146                          uint64_t offset,
147                          void *dst,
148                          uint64_t dst_len,
149                          Error &error)
150 {
151     if (IsHost())
152         return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
153     else if (m_remote_platform_sp)
154         return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
155     else
156         return Platform::ReadFile(fd, offset, dst, dst_len, error);
157 }
158 
159 uint64_t
160 PlatformPOSIX::WriteFile (lldb::user_id_t fd,
161                           uint64_t offset,
162                           const void* src,
163                           uint64_t src_len,
164                           Error &error)
165 {
166     if (IsHost())
167         return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
168     else if (m_remote_platform_sp)
169         return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
170     else
171         return Platform::WriteFile(fd, offset, src, src_len, error);
172 }
173 
174 static uint32_t
175 chown_file(Platform *platform,
176            const char* path,
177            uint32_t uid = UINT32_MAX,
178            uint32_t gid = UINT32_MAX)
179 {
180     if (!platform || !path || *path == 0)
181         return UINT32_MAX;
182 
183     if (uid == UINT32_MAX && gid == UINT32_MAX)
184         return 0;   // pretend I did chown correctly - actually I just didn't care
185 
186     StreamString command;
187     command.PutCString("chown ");
188     if (uid != UINT32_MAX)
189         command.Printf("%d",uid);
190     if (gid != UINT32_MAX)
191         command.Printf(":%d",gid);
192     command.Printf("%s",path);
193     int status;
194     platform->RunShellCommand(command.GetData(),
195                               NULL,
196                               &status,
197                               NULL,
198                               NULL,
199                               10);
200     return status;
201 }
202 
203 lldb_private::Error
204 PlatformPOSIX::PutFile (const lldb_private::FileSpec& source,
205                          const lldb_private::FileSpec& destination,
206                          uint32_t uid,
207                          uint32_t gid)
208 {
209     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
210 
211     if (IsHost())
212     {
213         if (FileSpec::Equal(source, destination, true))
214             return Error();
215         // cp src dst
216         // chown uid:gid dst
217         std::string src_path (source.GetPath());
218         if (src_path.empty())
219             return Error("unable to get file path for source");
220         std::string dst_path (destination.GetPath());
221         if (dst_path.empty())
222             return Error("unable to get file path for destination");
223         StreamString command;
224         command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
225         int status;
226         RunShellCommand(command.GetData(),
227                         NULL,
228                         &status,
229                         NULL,
230                         NULL,
231                         10);
232         if (status != 0)
233             return Error("unable to perform copy");
234         if (uid == UINT32_MAX && gid == UINT32_MAX)
235             return Error();
236         if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
237             return Error("unable to perform chown");
238         return Error();
239     }
240     else if (m_remote_platform_sp)
241     {
242         if (GetSupportsRSync())
243         {
244             std::string src_path (source.GetPath());
245             if (src_path.empty())
246                 return Error("unable to get file path for source");
247             std::string dst_path (destination.GetPath());
248             if (dst_path.empty())
249                 return Error("unable to get file path for destination");
250             StreamString command;
251             if (GetIgnoresRemoteHostname())
252             {
253                 if (!GetRSyncPrefix())
254                     command.Printf("rsync %s %s %s",
255                                    GetRSyncOpts(),
256                                    src_path.c_str(),
257                                    dst_path.c_str());
258                 else
259                     command.Printf("rsync %s %s %s%s",
260                                    GetRSyncOpts(),
261                                    src_path.c_str(),
262                                    GetRSyncPrefix(),
263                                    dst_path.c_str());
264             }
265             else
266                 command.Printf("rsync %s %s %s:%s",
267                                GetRSyncOpts(),
268                                src_path.c_str(),
269                                GetHostname(),
270                                dst_path.c_str());
271             if (log)
272                 log->Printf("[PutFile] Running command: %s\n", command.GetData());
273             int retcode;
274             Host::RunShellCommand(command.GetData(),
275                                   NULL,
276                                   &retcode,
277                                   NULL,
278                                   NULL,
279                                   60);
280             if (retcode == 0)
281             {
282                 // Don't chown a local file for a remote system
283 //                if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
284 //                    return Error("unable to perform chown");
285                 return Error();
286             }
287             // if we are still here rsync has failed - let's try the slow way before giving up
288         }
289 
290         if (log)
291             log->Printf ("PlatformPOSIX::PutFile(src='%s', dst='%s', uid=%u, gid=%u)",
292                          source.GetPath().c_str(),
293                          destination.GetPath().c_str(),
294                          uid,
295                          gid); // REMOVE THIS PRINTF PRIOR TO CHECKIN
296         // open
297         // read, write, read, write, ...
298         // close
299         // chown uid:gid dst
300         if (log)
301             log->Printf("[PutFile] Using block by block transfer....\n");
302 
303         uint32_t source_open_options = File::eOpenOptionRead;
304         if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink)
305             source_open_options |= File::eOpenoptionDontFollowSymlinks;
306 
307         File source_file(source, source_open_options, lldb::eFilePermissionsUserRW);
308         Error error;
309         uint32_t permissions = source_file.GetPermissions(error);
310         if (permissions == 0)
311             permissions = lldb::eFilePermissionsFileDefault;
312 
313         if (!source_file.IsValid())
314             return Error("unable to open source file");
315         lldb::user_id_t dest_file = OpenFile (destination,
316                                               File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
317                                               permissions,
318                                               error);
319         if (log)
320             log->Printf ("dest_file = %" PRIu64 "\n", dest_file);
321         if (error.Fail())
322             return error;
323         if (dest_file == UINT64_MAX)
324             return Error("unable to open target file");
325         lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
326         uint64_t offset = 0;
327         while (error.Success())
328         {
329             size_t bytes_read = buffer_sp->GetByteSize();
330             error = source_file.Read(buffer_sp->GetBytes(), bytes_read);
331             if (bytes_read)
332             {
333                 const uint64_t bytes_written = WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);
334                 offset += bytes_written;
335                 if (bytes_written != bytes_read)
336                 {
337                     // We didn't write the correct numbe of bytes, so adjust
338                     // the file position in the source file we are reading from...
339                     source_file.SeekFromStart(offset);
340                 }
341             }
342             else
343                 break;
344         }
345         CloseFile(dest_file, error);
346         if (uid == UINT32_MAX && gid == UINT32_MAX)
347             return error;
348         // This is remopve, don't chown a local file...
349 //        std::string dst_path (destination.GetPath());
350 //        if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
351 //            return Error("unable to perform chown");
352 
353 
354         uint64_t src_md5[2];
355         uint64_t dst_md5[2];
356 
357         if (FileSystem::CalculateMD5 (source, src_md5[0], src_md5[1]) && CalculateMD5 (destination, dst_md5[0], dst_md5[1]))
358         {
359             if (src_md5[0] != dst_md5[0] || src_md5[1] != dst_md5[1])
360             {
361                 error.SetErrorString("md5 checksum of installed file doesn't match, installation failed");
362             }
363         }
364         return error;
365     }
366     return Platform::PutFile(source,destination,uid,gid);
367 }
368 
369 lldb::user_id_t
370 PlatformPOSIX::GetFileSize (const FileSpec& file_spec)
371 {
372     if (IsHost())
373         return FileSystem::GetFileSize(file_spec);
374     else if (m_remote_platform_sp)
375         return m_remote_platform_sp->GetFileSize(file_spec);
376     else
377         return Platform::GetFileSize(file_spec);
378 }
379 
380 Error
381 PlatformPOSIX::CreateSymlink(const char *src, const char *dst)
382 {
383     if (IsHost())
384         return FileSystem::Symlink(src, dst);
385     else if (m_remote_platform_sp)
386         return m_remote_platform_sp->CreateSymlink(src, dst);
387     else
388         return Platform::CreateSymlink(src, dst);
389 }
390 
391 bool
392 PlatformPOSIX::GetFileExists (const FileSpec& file_spec)
393 {
394     if (IsHost())
395         return file_spec.Exists();
396     else if (m_remote_platform_sp)
397         return m_remote_platform_sp->GetFileExists(file_spec);
398     else
399         return Platform::GetFileExists(file_spec);
400 }
401 
402 Error
403 PlatformPOSIX::Unlink (const char *path)
404 {
405     if (IsHost())
406         return FileSystem::Unlink(path);
407     else if (m_remote_platform_sp)
408         return m_remote_platform_sp->Unlink(path);
409     else
410         return Platform::Unlink(path);
411 }
412 
413 lldb_private::Error
414 PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */,
415                         const lldb_private::FileSpec& destination /* local file path */)
416 {
417     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
418 
419     // Check the args, first.
420     std::string src_path (source.GetPath());
421     if (src_path.empty())
422         return Error("unable to get file path for source");
423     std::string dst_path (destination.GetPath());
424     if (dst_path.empty())
425         return Error("unable to get file path for destination");
426     if (IsHost())
427     {
428         if (FileSpec::Equal(source, destination, true))
429             return Error("local scenario->source and destination are the same file path: no operation performed");
430         // cp src dst
431         StreamString cp_command;
432         cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
433         int status;
434         RunShellCommand(cp_command.GetData(),
435                         NULL,
436                         &status,
437                         NULL,
438                         NULL,
439                         10);
440         if (status != 0)
441             return Error("unable to perform copy");
442         return Error();
443     }
444     else if (m_remote_platform_sp)
445     {
446         if (GetSupportsRSync())
447         {
448             StreamString command;
449             if (GetIgnoresRemoteHostname())
450             {
451                 if (!GetRSyncPrefix())
452                     command.Printf("rsync %s %s %s",
453                                    GetRSyncOpts(),
454                                    src_path.c_str(),
455                                    dst_path.c_str());
456                 else
457                     command.Printf("rsync %s %s%s %s",
458                                    GetRSyncOpts(),
459                                    GetRSyncPrefix(),
460                                    src_path.c_str(),
461                                    dst_path.c_str());
462             }
463             else
464                 command.Printf("rsync %s %s:%s %s",
465                                GetRSyncOpts(),
466                                m_remote_platform_sp->GetHostname(),
467                                src_path.c_str(),
468                                dst_path.c_str());
469             if (log)
470                 log->Printf("[GetFile] Running command: %s\n", command.GetData());
471             int retcode;
472             Host::RunShellCommand(command.GetData(),
473                                   NULL,
474                                   &retcode,
475                                   NULL,
476                                   NULL,
477                                   60);
478             if (retcode == 0)
479                 return Error();
480             // If we are here, rsync has failed - let's try the slow way before giving up
481         }
482         // open src and dst
483         // read/write, read/write, read/write, ...
484         // close src
485         // close dst
486         if (log)
487             log->Printf("[GetFile] Using block by block transfer....\n");
488         Error error;
489         user_id_t fd_src = OpenFile (source,
490                                      File::eOpenOptionRead,
491                                      lldb::eFilePermissionsFileDefault,
492                                      error);
493 
494         if (fd_src == UINT64_MAX)
495             return Error("unable to open source file");
496 
497         uint32_t permissions = 0;
498         error = GetFilePermissions(source.GetPath().c_str(), permissions);
499 
500         if (permissions == 0)
501             permissions = lldb::eFilePermissionsFileDefault;
502 
503         user_id_t fd_dst = FileCache::GetInstance().OpenFile(
504             destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, permissions,
505             error);
506 
507         if (fd_dst == UINT64_MAX)
508         {
509             if (error.Success())
510                 error.SetErrorString("unable to open destination file");
511         }
512 
513         if (error.Success())
514         {
515             lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
516             uint64_t offset = 0;
517             error.Clear();
518             while (error.Success())
519             {
520                 const uint64_t n_read = ReadFile (fd_src,
521                                                   offset,
522                                                   buffer_sp->GetBytes(),
523                                                   buffer_sp->GetByteSize(),
524                                                   error);
525                 if (error.Fail())
526                     break;
527                 if (n_read == 0)
528                     break;
529                 if (FileCache::GetInstance().WriteFile(fd_dst, offset, buffer_sp->GetBytes(), n_read, error) != n_read)
530                 {
531                     if (!error.Fail())
532                         error.SetErrorString("unable to write to destination file");
533                     break;
534                 }
535                 offset += n_read;
536             }
537         }
538         // Ignore the close error of src.
539         if (fd_src != UINT64_MAX)
540             CloseFile(fd_src, error);
541         // And close the dst file descriptot.
542         if (fd_dst != UINT64_MAX && !FileCache::GetInstance().CloseFile(fd_dst, error))
543         {
544             if (!error.Fail())
545                 error.SetErrorString("unable to close destination file");
546 
547         }
548         return error;
549     }
550     return Platform::GetFile(source,destination);
551 }
552 
553 std::string
554 PlatformPOSIX::GetPlatformSpecificConnectionInformation()
555 {
556     StreamString stream;
557     if (GetSupportsRSync())
558     {
559         stream.PutCString("rsync");
560         if ( (GetRSyncOpts() && *GetRSyncOpts()) ||
561              (GetRSyncPrefix() && *GetRSyncPrefix()) ||
562              GetIgnoresRemoteHostname())
563         {
564             stream.Printf(", options: ");
565             if (GetRSyncOpts() && *GetRSyncOpts())
566                 stream.Printf("'%s' ",GetRSyncOpts());
567             stream.Printf(", prefix: ");
568             if (GetRSyncPrefix() && *GetRSyncPrefix())
569                 stream.Printf("'%s' ",GetRSyncPrefix());
570             if (GetIgnoresRemoteHostname())
571                 stream.Printf("ignore remote-hostname ");
572         }
573     }
574     if (GetSupportsSSH())
575     {
576         stream.PutCString("ssh");
577         if (GetSSHOpts() && *GetSSHOpts())
578             stream.Printf(", options: '%s' ",GetSSHOpts());
579     }
580     if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
581         stream.Printf("cache dir: %s",GetLocalCacheDirectory());
582     if (stream.GetSize())
583         return stream.GetData();
584     else
585         return "";
586 }
587 
588 bool
589 PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec,
590                             uint64_t &low,
591                             uint64_t &high)
592 {
593     if (IsHost())
594         return Platform::CalculateMD5 (file_spec, low, high);
595     if (m_remote_platform_sp)
596         return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
597     return false;
598 }
599 
600 lldb_private::ConstString
601 PlatformPOSIX::GetRemoteWorkingDirectory()
602 {
603     if (IsRemote() && m_remote_platform_sp)
604         return m_remote_platform_sp->GetRemoteWorkingDirectory();
605     else
606         return Platform::GetRemoteWorkingDirectory();
607 }
608 
609 bool
610 PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path)
611 {
612     if (IsRemote() && m_remote_platform_sp)
613         return m_remote_platform_sp->SetRemoteWorkingDirectory(path);
614     else
615         return Platform::SetRemoteWorkingDirectory(path);
616 }
617 
618 bool
619 PlatformPOSIX::GetRemoteOSVersion ()
620 {
621     if (m_remote_platform_sp)
622         return m_remote_platform_sp->GetOSVersion (m_major_os_version,
623                                                    m_minor_os_version,
624                                                    m_update_os_version);
625     return false;
626 }
627 
628 bool
629 PlatformPOSIX::GetRemoteOSBuildString (std::string &s)
630 {
631     if (m_remote_platform_sp)
632         return m_remote_platform_sp->GetRemoteOSBuildString (s);
633     s.clear();
634     return false;
635 }
636 
637 size_t
638 PlatformPOSIX::GetEnvironment (StringList &env)
639 {
640     if (IsRemote())
641     {
642         if (m_remote_platform_sp)
643             return m_remote_platform_sp->GetEnvironment(env);
644         return 0;
645     }
646     return Host::GetEnvironment(env);
647 }
648 
649 bool
650 PlatformPOSIX::GetRemoteOSKernelDescription (std::string &s)
651 {
652     if (m_remote_platform_sp)
653         return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
654     s.clear();
655     return false;
656 }
657 
658 // Remote Platform subclasses need to override this function
659 ArchSpec
660 PlatformPOSIX::GetRemoteSystemArchitecture ()
661 {
662     if (m_remote_platform_sp)
663         return m_remote_platform_sp->GetRemoteSystemArchitecture ();
664     return ArchSpec();
665 }
666 
667 const char *
668 PlatformPOSIX::GetHostname ()
669 {
670     if (IsHost())
671         return Platform::GetHostname();
672 
673     if (m_remote_platform_sp)
674         return m_remote_platform_sp->GetHostname ();
675     return NULL;
676 }
677 
678 const char *
679 PlatformPOSIX::GetUserName (uint32_t uid)
680 {
681     // Check the cache in Platform in case we have already looked this uid up
682     const char *user_name = Platform::GetUserName(uid);
683     if (user_name)
684         return user_name;
685 
686     if (IsRemote() && m_remote_platform_sp)
687         return m_remote_platform_sp->GetUserName(uid);
688     return NULL;
689 }
690 
691 const char *
692 PlatformPOSIX::GetGroupName (uint32_t gid)
693 {
694     const char *group_name = Platform::GetGroupName(gid);
695     if (group_name)
696         return group_name;
697 
698     if (IsRemote() && m_remote_platform_sp)
699         return m_remote_platform_sp->GetGroupName(gid);
700     return NULL;
701 }
702 
703 Error
704 PlatformPOSIX::ConnectRemote (Args& args)
705 {
706     Error error;
707     if (IsHost())
708     {
709         error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
710     }
711     else
712     {
713         if (!m_remote_platform_sp)
714             m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error);
715 
716         if (m_remote_platform_sp && error.Success())
717             error = m_remote_platform_sp->ConnectRemote (args);
718         else
719             error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
720 
721         if (error.Fail())
722             m_remote_platform_sp.reset();
723     }
724 
725     if (error.Success() && m_remote_platform_sp)
726     {
727         if (m_options.get())
728         {
729             OptionGroupOptions* options = m_options.get();
730             OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r');
731             OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s');
732             OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c');
733 
734             if (m_rsync_options->m_rsync)
735             {
736                 SetSupportsRSync(true);
737                 SetRSyncOpts(m_rsync_options->m_rsync_opts.c_str());
738                 SetRSyncPrefix(m_rsync_options->m_rsync_prefix.c_str());
739                 SetIgnoresRemoteHostname(m_rsync_options->m_ignores_remote_hostname);
740             }
741             if (m_ssh_options->m_ssh)
742             {
743                 SetSupportsSSH(true);
744                 SetSSHOpts(m_ssh_options->m_ssh_opts.c_str());
745             }
746             SetLocalCacheDirectory(m_cache_options->m_cache_dir.c_str());
747         }
748     }
749 
750     return error;
751 }
752 
753 Error
754 PlatformPOSIX::DisconnectRemote ()
755 {
756     Error error;
757 
758     if (IsHost())
759     {
760         error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString());
761     }
762     else
763     {
764         if (m_remote_platform_sp)
765             error = m_remote_platform_sp->DisconnectRemote ();
766         else
767             error.SetErrorString ("the platform is not currently connected");
768     }
769     return error;
770 }
771 
772 lldb::ProcessSP
773 PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info,
774                               Debugger &debugger,
775                               Target *target,       // Can be NULL, if NULL create a new target, else use existing one
776                               Listener &listener,
777                               Error &error)
778 {
779     ProcessSP process_sp;
780 
781     if (IsHost())
782     {
783         // We are going to hand this process off to debugserver which will be in charge of setting the exit status.
784         // We still need to reap it from lldb but if we let the monitor thread also set the exit status, we set up a
785         // race between debugserver & us for who will find out about the debugged process's death.
786         launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus);
787         process_sp = Platform::DebugProcess (launch_info, debugger, target, listener, error);
788     }
789     else
790     {
791         if (m_remote_platform_sp)
792             process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, listener, error);
793         else
794             error.SetErrorString ("the platform is not currently connected");
795     }
796     return process_sp;
797 
798 }
799 
800 void
801 PlatformPOSIX::CalculateTrapHandlerSymbolNames ()
802 {
803     m_trap_handlers.push_back (ConstString ("_sigtramp"));
804 }
805