1 //===-- HostInfoPosix.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 #if !defined(LLDB_DISABLE_PYTHON)
11 #include "Plugins/ScriptInterpreter/Python/lldb-python.h"
12 #endif
13 
14 #include "lldb/Core/Log.h"
15 #include "lldb/Host/posix/HostInfoPosix.h"
16 
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/Support/raw_ostream.h"
19 
20 #include <grp.h>
21 #include <limits.h>
22 #include <mutex>
23 #include <netdb.h>
24 #include <pwd.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 
29 using namespace lldb_private;
30 
31 size_t HostInfoPosix::GetPageSize() { return ::getpagesize(); }
32 
33 bool HostInfoPosix::GetHostname(std::string &s) {
34   char hostname[PATH_MAX];
35   hostname[sizeof(hostname) - 1] = '\0';
36   if (::gethostname(hostname, sizeof(hostname) - 1) == 0) {
37     struct hostent *h = ::gethostbyname(hostname);
38     if (h)
39       s.assign(h->h_name);
40     else
41       s.assign(hostname);
42     return true;
43   }
44   return false;
45 }
46 
47 #ifdef __ANDROID_NDK__
48 #include <android/api-level.h>
49 #endif
50 #if defined(__ANDROID_API__) && __ANDROID_API__ < 21
51 #define USE_GETPWUID
52 #endif
53 
54 #ifdef USE_GETPWUID
55 static std::mutex s_getpwuid_lock;
56 #endif
57 
58 const char *HostInfoPosix::LookupUserName(uint32_t uid,
59                                           std::string &user_name) {
60 #ifdef USE_GETPWUID
61   // getpwuid_r is missing from android-9
62   // make getpwuid thread safe with a mutex
63   std::lock_guard<std::mutex> lock(s_getpwuid_lock);
64   struct passwd *user_info_ptr = ::getpwuid(uid);
65   if (user_info_ptr) {
66     user_name.assign(user_info_ptr->pw_name);
67     return user_name.c_str();
68   }
69 #else
70   struct passwd user_info;
71   struct passwd *user_info_ptr = &user_info;
72   char user_buffer[PATH_MAX];
73   size_t user_buffer_size = sizeof(user_buffer);
74   if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size,
75                    &user_info_ptr) == 0) {
76     if (user_info_ptr) {
77       user_name.assign(user_info_ptr->pw_name);
78       return user_name.c_str();
79     }
80   }
81 #endif
82   user_name.clear();
83   return nullptr;
84 }
85 
86 const char *HostInfoPosix::LookupGroupName(uint32_t gid,
87                                            std::string &group_name) {
88 #ifndef __ANDROID__
89   char group_buffer[PATH_MAX];
90   size_t group_buffer_size = sizeof(group_buffer);
91   struct group group_info;
92   struct group *group_info_ptr = &group_info;
93   // Try the threadsafe version first
94   if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size,
95                    &group_info_ptr) == 0) {
96     if (group_info_ptr) {
97       group_name.assign(group_info_ptr->gr_name);
98       return group_name.c_str();
99     }
100   } else {
101     // The threadsafe version isn't currently working for me on darwin, but the
102     // non-threadsafe version
103     // is, so I am calling it below.
104     group_info_ptr = ::getgrgid(gid);
105     if (group_info_ptr) {
106       group_name.assign(group_info_ptr->gr_name);
107       return group_name.c_str();
108     }
109   }
110   group_name.clear();
111 #else
112   assert(false && "getgrgid_r() not supported on Android");
113 #endif
114   return NULL;
115 }
116 
117 uint32_t HostInfoPosix::GetUserID() { return getuid(); }
118 
119 uint32_t HostInfoPosix::GetGroupID() { return getgid(); }
120 
121 uint32_t HostInfoPosix::GetEffectiveUserID() { return geteuid(); }
122 
123 uint32_t HostInfoPosix::GetEffectiveGroupID() { return getegid(); }
124 
125 FileSpec HostInfoPosix::GetDefaultShell() { return FileSpec("/bin/sh", false); }
126 
127 bool HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec) {
128   Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
129 
130   FileSpec lldb_file_spec;
131   if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
132     return false;
133 
134   char raw_path[PATH_MAX];
135   lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
136 
137   // Most Posix systems (e.g. Linux/*BSD) will attempt to replace a */lib with
138   // */bin as the base
139   // directory for helper exe programs.  This will fail if the /lib and /bin
140   // directories are
141   // rooted in entirely different trees.
142   if (log)
143     log->Printf("HostInfoPosix::ComputeSupportExeDirectory() attempting to "
144                 "derive the bin path (ePathTypeSupportExecutableDir) from "
145                 "this path: %s",
146                 raw_path);
147   char *lib_pos = ::strstr(raw_path, "/lib");
148   if (lib_pos != nullptr) {
149     // Now write in bin in place of lib.
150     ::snprintf(lib_pos, PATH_MAX - (lib_pos - raw_path), "/bin");
151 
152     if (log)
153       log->Printf("Host::%s() derived the bin path as: %s", __FUNCTION__,
154                   raw_path);
155   } else {
156     if (log)
157       log->Printf("Host::%s() failed to find /lib/liblldb within the shared "
158                   "lib path, bailing on bin path construction",
159                   __FUNCTION__);
160   }
161   file_spec.GetDirectory().SetCString(raw_path);
162   return (bool)file_spec.GetDirectory();
163 }
164 
165 bool HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec) {
166   FileSpec temp_file("/opt/local/include/lldb", false);
167   file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
168   return true;
169 }
170 
171 bool HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec) {
172 #ifndef LLDB_DISABLE_PYTHON
173   FileSpec lldb_file_spec;
174   if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
175     return false;
176 
177   char raw_path[PATH_MAX];
178   lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
179 
180 #if defined(LLDB_PYTHON_RELATIVE_LIBDIR)
181   // Build the path by backing out of the lib dir, then building
182   // with whatever the real python interpreter uses.  (e.g. lib
183   // for most, lib64 on RHEL x86_64).
184   char python_path[PATH_MAX];
185   ::snprintf(python_path, sizeof(python_path), "%s/../%s", raw_path,
186              LLDB_PYTHON_RELATIVE_LIBDIR);
187 
188   char final_path[PATH_MAX];
189   realpath(python_path, final_path);
190   file_spec.GetDirectory().SetCString(final_path);
191 
192   return true;
193 #else
194   llvm::SmallString<256> python_version_dir;
195   llvm::raw_svector_ostream os(python_version_dir);
196   os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION
197      << "/site-packages";
198 
199   // We may get our string truncated. Should we protect this with an assert?
200   ::strncat(raw_path, python_version_dir.c_str(),
201             sizeof(raw_path) - strlen(raw_path) - 1);
202 
203   file_spec.GetDirectory().SetCString(raw_path);
204   return true;
205 #endif
206 #else
207   return false;
208 #endif
209 }
210 
211 bool HostInfoPosix::GetEnvironmentVar(const std::string &var_name,
212                                       std::string &var) {
213   if (const char *pvar = ::getenv(var_name.c_str())) {
214     var = std::string(pvar);
215     return true;
216   }
217   return false;
218 }
219