HostInfoPosix.cpp revision 296417
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
29using namespace lldb_private;
30
31size_t
32HostInfoPosix::GetPageSize()
33{
34    return ::getpagesize();
35}
36
37bool
38HostInfoPosix::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
62static std::mutex s_getpwuid_lock;
63#endif
64
65const char *
66HostInfoPosix::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
96const char *
97HostInfoPosix::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
131uint32_t
132HostInfoPosix::GetUserID()
133{
134    return getuid();
135}
136
137uint32_t
138HostInfoPosix::GetGroupID()
139{
140    return getgid();
141}
142
143uint32_t
144HostInfoPosix::GetEffectiveUserID()
145{
146    return geteuid();
147}
148
149uint32_t
150HostInfoPosix::GetEffectiveGroupID()
151{
152    return getegid();
153}
154
155FileSpec
156HostInfoPosix::GetDefaultShell()
157{
158    return FileSpec("/bin/sh", false);
159}
160
161bool
162HostInfoPosix::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
199bool
200HostInfoPosix::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
207bool
208HostInfoPosix::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