LLDB mainline
HostInfoPosix.cpp
Go to the documentation of this file.
1//===-- HostInfoPosix.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Host/Config.h"
12#include "lldb/Host/HostInfo.h"
13#include "lldb/Utility/Log.h"
15#include "llvm/ADT/SmallString.h"
16#include "llvm/ADT/Twine.h"
17#include "llvm/Support/Path.h"
18#include "llvm/Support/raw_ostream.h"
19
20#include <climits>
21#include <cstdio>
22#include <cstdlib>
23#include <cstring>
24#include <grp.h>
25#include <mutex>
26#include <optional>
27#include <pwd.h>
28#include <sys/types.h>
29#include <sys/utsname.h>
30#include <unistd.h>
31
32using namespace lldb_private;
33
34namespace {
35struct HostInfoPosixFields {
36 llvm::once_flag m_os_version_once_flag;
37 llvm::VersionTuple m_os_version;
38};
39} // namespace
40
41llvm::VersionTuple HostInfoPosix::GetOSVersion() {
42 static HostInfoPosixFields *g_fields = new HostInfoPosixFields();
43 assert(g_fields && "Missing call to Initialize?");
44 llvm::call_once(g_fields->m_os_version_once_flag, []() {
45 struct utsname un;
46 if (uname(&un) != 0)
47 return;
48
49 llvm::StringRef release = un.release;
50 // The Linux kernel release string can include a lot of stuff (e.g.
51 // 4.9.0-6-amd64). We're only interested in the numbered prefix.
52 release = release.substr(0, release.find_first_not_of("0123456789."));
53 g_fields->m_os_version.tryParse(release);
54 });
55
56 return g_fields->m_os_version;
57}
58
59size_t HostInfoPosix::GetPageSize() { return ::getpagesize(); }
60
61bool HostInfoPosix::GetHostname(std::string &s) {
62 char hostname[PATH_MAX];
63 hostname[sizeof(hostname) - 1] = '\0';
64 if (::gethostname(hostname, sizeof(hostname) - 1) == 0) {
65 s.assign(hostname);
66 return true;
67 }
68 return false;
69}
70
71std::optional<std::string> HostInfoPosix::GetOSKernelDescription() {
72 struct utsname un;
73 if (uname(&un) < 0)
74 return std::nullopt;
75
76 return std::string(un.version);
77}
78
79std::optional<std::string> HostInfoPosix::GetOSBuildString() {
80 struct utsname un;
81 ::memset(&un, 0, sizeof(utsname));
82
83 if (uname(&un) < 0)
84 return std::nullopt;
85
86 return std::string(un.release);
87}
88
89#ifdef __ANDROID__
90#include <android/api-level.h>
91#endif
92#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
93#define USE_GETPWUID
94#endif
95
96namespace {
97class PosixUserIDResolver : public UserIDResolver {
98protected:
99 std::optional<std::string> DoGetUserName(id_t uid) override;
100 std::optional<std::string> DoGetGroupName(id_t gid) override;
101};
102} // namespace
103
105 std::string username;
106 std::string shell;
107};
108
109static std::optional<PasswdEntry> GetPassword(id_t uid) {
110#ifdef USE_GETPWUID
111 // getpwuid_r is missing from android-9
112 // The caller should provide some thread safety by making sure no one calls
113 // this function concurrently, because using getpwuid is ultimately not
114 // thread-safe as we don't know who else might be calling it.
115 if (auto *user_info_ptr = ::getpwuid(uid))
116 return PasswdEntry{user_info_ptr->pw_name, user_info_ptr->pw_shell};
117#else
118 struct passwd user_info;
119 struct passwd *user_info_ptr = &user_info;
120 char user_buffer[PATH_MAX];
121 size_t user_buffer_size = sizeof(user_buffer);
122 if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size,
123 &user_info_ptr) == 0 &&
124 user_info_ptr) {
125 return PasswdEntry{user_info_ptr->pw_name, user_info_ptr->pw_shell};
126 }
127#endif
128 return std::nullopt;
129}
130
131std::optional<std::string> PosixUserIDResolver::DoGetUserName(id_t uid) {
132 if (std::optional<PasswdEntry> password = GetPassword(uid))
133 return password->username;
134 return std::nullopt;
135}
136
137std::optional<std::string> PosixUserIDResolver::DoGetGroupName(id_t gid) {
138#ifndef __ANDROID__
139 char group_buffer[PATH_MAX];
140 size_t group_buffer_size = sizeof(group_buffer);
141 struct group group_info;
142 struct group *group_info_ptr = &group_info;
143 // Try the threadsafe version first
144 if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size,
145 &group_info_ptr) == 0) {
146 if (group_info_ptr)
147 return std::string(group_info_ptr->gr_name);
148 } else {
149 // The threadsafe version isn't currently working for me on darwin, but the
150 // non-threadsafe version is, so I am calling it below.
151 group_info_ptr = ::getgrgid(gid);
152 if (group_info_ptr)
153 return std::string(group_info_ptr->gr_name);
154 }
155#endif
156 return std::nullopt;
157}
158
159static llvm::ManagedStatic<PosixUserIDResolver> g_user_id_resolver;
160
162 return *g_user_id_resolver;
163}
164
165uint32_t HostInfoPosix::GetUserID() { return getuid(); }
166
167uint32_t HostInfoPosix::GetGroupID() { return getgid(); }
168
169uint32_t HostInfoPosix::GetEffectiveUserID() { return geteuid(); }
170
171uint32_t HostInfoPosix::GetEffectiveGroupID() { return getegid(); }
172
174 if (const char *v = ::getenv("SHELL"))
175 return FileSpec(v);
176 if (std::optional<PasswdEntry> password = GetPassword(::geteuid()))
177 return FileSpec(password->shell);
178 return FileSpec("/bin/sh");
179}
180
182 if (ComputePathRelativeToLibrary(file_spec, "/bin") &&
183 file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec))
184 return true;
185 file_spec.SetDirectory(HostInfo::GetProgramFileSpec().GetDirectory());
186 return !file_spec.GetDirectory().IsEmpty();
187}
188
190 FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins");
191 FileSystem::Instance().Resolve(temp_file);
192 file_spec.SetDirectory(temp_file.GetPath());
193 return true;
194}
195
197 // XDG Base Directory Specification
198 // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If
199 // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
200 const char *xdg_data_home = getenv("XDG_DATA_HOME");
201 if (xdg_data_home && xdg_data_home[0]) {
202 std::string user_plugin_dir(xdg_data_home);
203 user_plugin_dir += "/lldb";
204 file_spec.SetDirectory(user_plugin_dir.c_str());
205 } else
206 file_spec.SetDirectory("~/.local/share/lldb");
207 return true;
208}
209
211 FileSpec temp_file("/opt/local/include/lldb");
212 file_spec.SetDirectory(temp_file.GetPath());
213 return true;
214}
215
216bool HostInfoPosix::GetEnvironmentVar(const std::string &var_name,
217 std::string &var) {
218 if (const char *pvar = ::getenv(var_name.c_str())) {
219 var = std::string(pvar);
220 return true;
221 }
222 return false;
223}
static HostInfoBaseFields * g_fields
static llvm::ManagedStatic< PosixUserIDResolver > g_user_id_resolver
static std::optional< PasswdEntry > GetPassword(id_t uid)
bool IsEmpty() const
Test for empty string.
Definition: ConstString.h:304
A file utility class.
Definition: FileSpec.h:56
void SetDirectory(ConstString directory)
Directory string set accessor.
Definition: FileSpec.cpp:335
const ConstString & GetDirectory() const
Directory string const get accessor.
Definition: FileSpec.h:223
bool IsAbsolute() const
Returns true if the filespec represents an absolute path.
Definition: FileSpec.cpp:511
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:367
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
bool Exists(const FileSpec &file_spec) const
Returns whether the given file exists.
static FileSystem & Instance()
static bool ComputePathRelativeToLibrary(FileSpec &file_spec, llvm::StringRef dir)
static std::optional< std::string > GetOSBuildString()
static bool ComputeSupportExeDirectory(FileSpec &file_spec)
static bool GetHostname(std::string &s)
static bool ComputeSystemPluginsDirectory(FileSpec &file_spec)
static std::optional< std::string > GetOSKernelDescription()
static FileSpec GetDefaultShell()
static uint32_t GetEffectiveUserID()
static llvm::VersionTuple GetOSVersion()
static bool GetEnvironmentVar(const std::string &var_name, std::string &var)
static uint32_t GetGroupID()
static bool ComputeUserPluginsDirectory(FileSpec &file_spec)
static uint32_t GetEffectiveGroupID()
static UserIDResolver & GetUserIDResolver()
static bool ComputeHeaderDirectory(FileSpec &file_spec)
An abstract interface for things that know how to map numeric user/group IDs into names.
A class that represents a running process on the host machine.
std::string shell
std::string username
#define PATH_MAX