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
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"
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(flag&: g_fields->m_os_version_once_flag, F: []() {
45 struct utsname un;
46 if (uname(name: &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(Start: 0, N: release.find_first_not_of(Chars: "0123456789."));
53 g_fields->m_os_version.tryParse(string: 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(name: hostname, len: sizeof(hostname) - 1) == 0) {
65 s.assign(s: hostname);
66 return true;
67 }
68 return false;
69}
70
71std::optional<std::string> HostInfoPosix::GetOSKernelDescription() {
72 struct utsname un;
73 if (uname(name: &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(s: &un, c: 0, n: sizeof(utsname));
82
83 if (uname(name: &un) < 0)
84 return std::nullopt;
85
86 return std::string(un.release);
87}
88
89namespace {
90class PosixUserIDResolver : public UserIDResolver {
91protected:
92 std::optional<std::string> DoGetUserName(id_t uid) override;
93 std::optional<std::string> DoGetGroupName(id_t gid) override;
94};
95} // namespace
96
97struct PasswdEntry {
98 std::string username;
99 std::string shell;
100};
101
102static std::optional<PasswdEntry> GetPassword(id_t uid) {
103 struct passwd user_info;
104 struct passwd *user_info_ptr = &user_info;
105 char user_buffer[PATH_MAX];
106 size_t user_buffer_size = sizeof(user_buffer);
107 if (::getpwuid_r(uid: uid, resultbuf: &user_info, buffer: user_buffer, buflen: user_buffer_size,
108 result: &user_info_ptr) == 0 &&
109 user_info_ptr) {
110 return PasswdEntry{.username: user_info_ptr->pw_name, .shell: user_info_ptr->pw_shell};
111 }
112 return std::nullopt;
113}
114
115std::optional<std::string> PosixUserIDResolver::DoGetUserName(id_t uid) {
116 if (std::optional<PasswdEntry> password = GetPassword(uid))
117 return password->username;
118 return std::nullopt;
119}
120
121std::optional<std::string> PosixUserIDResolver::DoGetGroupName(id_t gid) {
122#if !defined(__ANDROID__) || __ANDROID_API__ >= 24
123 char group_buffer[PATH_MAX];
124 size_t group_buffer_size = sizeof(group_buffer);
125 struct group group_info;
126 struct group *group_info_ptr = &group_info;
127 // Try the threadsafe version first
128 if (::getgrgid_r(gid: gid, resultbuf: &group_info, buffer: group_buffer, buflen: group_buffer_size,
129 result: &group_info_ptr) == 0) {
130 if (group_info_ptr)
131 return std::string(group_info_ptr->gr_name);
132 } else {
133 // The threadsafe version isn't currently working for me on darwin, but the
134 // non-threadsafe version is, so I am calling it below.
135 group_info_ptr = ::getgrgid(gid: gid);
136 if (group_info_ptr)
137 return std::string(group_info_ptr->gr_name);
138 }
139#endif
140 return std::nullopt;
141}
142
143static llvm::ManagedStatic<PosixUserIDResolver> g_user_id_resolver;
144
145UserIDResolver &HostInfoPosix::GetUserIDResolver() {
146 return *g_user_id_resolver;
147}
148
149uint32_t HostInfoPosix::GetUserID() { return getuid(); }
150
151uint32_t HostInfoPosix::GetGroupID() { return getgid(); }
152
153uint32_t HostInfoPosix::GetEffectiveUserID() { return geteuid(); }
154
155uint32_t HostInfoPosix::GetEffectiveGroupID() { return getegid(); }
156
157FileSpec HostInfoPosix::GetDefaultShell() {
158 if (const char *v = ::getenv(name: "SHELL"))
159 return FileSpec(v);
160 if (std::optional<PasswdEntry> password = GetPassword(uid: ::geteuid()))
161 return FileSpec(password->shell);
162 return FileSpec("/bin/sh");
163}
164
165bool HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec) {
166 if (ComputePathRelativeToLibrary(file_spec, dir: "/bin") &&
167 file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec))
168 return true;
169 file_spec.SetDirectory(HostInfo::GetProgramFileSpec().GetDirectory());
170 return !file_spec.GetDirectory().IsEmpty();
171}
172
173bool HostInfoPosix::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
174 FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins");
175 FileSystem::Instance().Resolve(file_spec&: temp_file);
176 file_spec.SetDirectory(temp_file.GetPath());
177 return true;
178}
179
180bool HostInfoPosix::ComputeUserPluginsDirectory(FileSpec &file_spec) {
181 // XDG Base Directory Specification
182 // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If
183 // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
184 const char *xdg_data_home = getenv(name: "XDG_DATA_HOME");
185 if (xdg_data_home && xdg_data_home[0]) {
186 std::string user_plugin_dir(xdg_data_home);
187 user_plugin_dir += "/lldb";
188 file_spec.SetDirectory(user_plugin_dir.c_str());
189 } else
190 file_spec.SetDirectory("~/.local/share/lldb");
191 return true;
192}
193
194bool HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec) {
195 FileSpec temp_file("/opt/local/include/lldb");
196 file_spec.SetDirectory(temp_file.GetPath());
197 return true;
198}
199
200bool HostInfoPosix::GetEnvironmentVar(const std::string &var_name,
201 std::string &var) {
202 if (const char *pvar = ::getenv(name: var_name.c_str())) {
203 var = std::string(pvar);
204 return true;
205 }
206 return false;
207}
208

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/Host/posix/HostInfoPosix.cpp