[OptTable] Fix typo VALUE => VALUES (NFCI) (#121523)
[llvm-project.git] / lldb / source / Host / posix / HostInfoPosix.cpp
blob193f584900b63285786a6010dd454b7513ca52d9
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 //===----------------------------------------------------------------------===//
9 #include "lldb/Host/posix/HostInfoPosix.h"
10 #include "lldb/Host/Config.h"
11 #include "lldb/Host/FileSystem.h"
12 #include "lldb/Host/HostInfo.h"
13 #include "lldb/Utility/Log.h"
14 #include "lldb/Utility/UserIDResolver.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"
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>
32 using namespace lldb_private;
34 namespace {
35 struct HostInfoPosixFields {
36 llvm::once_flag m_os_version_once_flag;
37 llvm::VersionTuple m_os_version;
39 } // namespace
41 llvm::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;
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 });
56 return g_fields->m_os_version;
59 size_t HostInfoPosix::GetPageSize() { return ::getpagesize(); }
61 bool 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;
68 return false;
71 std::optional<std::string> HostInfoPosix::GetOSKernelDescription() {
72 struct utsname un;
73 if (uname(&un) < 0)
74 return std::nullopt;
76 return std::string(un.version);
79 std::optional<std::string> HostInfoPosix::GetOSBuildString() {
80 struct utsname un;
81 ::memset(&un, 0, sizeof(utsname));
83 if (uname(&un) < 0)
84 return std::nullopt;
86 return std::string(un.release);
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
96 namespace {
97 class PosixUserIDResolver : public UserIDResolver {
98 protected:
99 std::optional<std::string> DoGetUserName(id_t uid) override;
100 std::optional<std::string> DoGetGroupName(id_t gid) override;
102 } // namespace
104 struct PasswdEntry {
105 std::string username;
106 std::string shell;
109 static 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};
127 #endif
128 return std::nullopt;
131 std::optional<std::string> PosixUserIDResolver::DoGetUserName(id_t uid) {
132 if (std::optional<PasswdEntry> password = GetPassword(uid))
133 return password->username;
134 return std::nullopt;
137 std::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);
155 #endif
156 return std::nullopt;
159 static llvm::ManagedStatic<PosixUserIDResolver> g_user_id_resolver;
161 UserIDResolver &HostInfoPosix::GetUserIDResolver() {
162 return *g_user_id_resolver;
165 uint32_t HostInfoPosix::GetUserID() { return getuid(); }
167 uint32_t HostInfoPosix::GetGroupID() { return getgid(); }
169 uint32_t HostInfoPosix::GetEffectiveUserID() { return geteuid(); }
171 uint32_t HostInfoPosix::GetEffectiveGroupID() { return getegid(); }
173 FileSpec HostInfoPosix::GetDefaultShell() {
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");
181 bool HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec) {
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();
189 bool HostInfoPosix::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
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;
196 bool HostInfoPosix::ComputeUserPluginsDirectory(FileSpec &file_spec) {
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;
210 bool HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec) {
211 FileSpec temp_file("/opt/local/include/lldb");
212 file_spec.SetDirectory(temp_file.GetPath());
213 return true;
216 bool 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;
222 return false;