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