1dda28197Spatrick //===-- HostInfoPosix.cpp -------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Host/posix/HostInfoPosix.h"
10061da546Spatrick #include "lldb/Utility/Log.h"
11061da546Spatrick #include "lldb/Utility/UserIDResolver.h"
12061da546Spatrick
13061da546Spatrick #include "llvm/ADT/SmallString.h"
14061da546Spatrick #include "llvm/ADT/Twine.h"
15061da546Spatrick #include "llvm/Support/Path.h"
16061da546Spatrick #include "llvm/Support/raw_ostream.h"
17061da546Spatrick
18be691f3bSpatrick #include <climits>
19be691f3bSpatrick #include <cstdlib>
20061da546Spatrick #include <grp.h>
21061da546Spatrick #include <mutex>
22*f6aab3d8Srobert #include <optional>
23061da546Spatrick #include <pwd.h>
24061da546Spatrick #include <sys/types.h>
25*f6aab3d8Srobert #include <sys/utsname.h>
26061da546Spatrick #include <unistd.h>
27061da546Spatrick
28061da546Spatrick using namespace lldb_private;
29061da546Spatrick
GetPageSize()30061da546Spatrick size_t HostInfoPosix::GetPageSize() { return ::getpagesize(); }
31061da546Spatrick
GetHostname(std::string & s)32061da546Spatrick bool HostInfoPosix::GetHostname(std::string &s) {
33061da546Spatrick char hostname[PATH_MAX];
34061da546Spatrick hostname[sizeof(hostname) - 1] = '\0';
35061da546Spatrick if (::gethostname(hostname, sizeof(hostname) - 1) == 0) {
36061da546Spatrick s.assign(hostname);
37061da546Spatrick return true;
38061da546Spatrick }
39061da546Spatrick return false;
40061da546Spatrick }
41061da546Spatrick
GetOSKernelDescription()42*f6aab3d8Srobert std::optional<std::string> HostInfoPosix::GetOSKernelDescription() {
43*f6aab3d8Srobert struct utsname un;
44*f6aab3d8Srobert if (uname(&un) < 0)
45*f6aab3d8Srobert return std::nullopt;
46*f6aab3d8Srobert
47*f6aab3d8Srobert return std::string(un.version);
48*f6aab3d8Srobert }
49*f6aab3d8Srobert
50061da546Spatrick #ifdef __ANDROID__
51061da546Spatrick #include <android/api-level.h>
52061da546Spatrick #endif
53061da546Spatrick #if defined(__ANDROID_API__) && __ANDROID_API__ < 21
54061da546Spatrick #define USE_GETPWUID
55061da546Spatrick #endif
56061da546Spatrick
57061da546Spatrick namespace {
58061da546Spatrick class PosixUserIDResolver : public UserIDResolver {
59061da546Spatrick protected:
60*f6aab3d8Srobert std::optional<std::string> DoGetUserName(id_t uid) override;
61*f6aab3d8Srobert std::optional<std::string> DoGetGroupName(id_t gid) override;
62061da546Spatrick };
63061da546Spatrick } // namespace
64061da546Spatrick
65061da546Spatrick struct PasswdEntry {
66061da546Spatrick std::string username;
67061da546Spatrick std::string shell;
68061da546Spatrick };
69061da546Spatrick
GetPassword(id_t uid)70*f6aab3d8Srobert static std::optional<PasswdEntry> GetPassword(id_t uid) {
71061da546Spatrick #ifdef USE_GETPWUID
72061da546Spatrick // getpwuid_r is missing from android-9
73061da546Spatrick // The caller should provide some thread safety by making sure no one calls
74061da546Spatrick // this function concurrently, because using getpwuid is ultimately not
75061da546Spatrick // thread-safe as we don't know who else might be calling it.
76061da546Spatrick if (auto *user_info_ptr = ::getpwuid(uid))
77061da546Spatrick return PasswdEntry{user_info_ptr->pw_name, user_info_ptr->pw_shell};
78061da546Spatrick #else
79061da546Spatrick struct passwd user_info;
80061da546Spatrick struct passwd *user_info_ptr = &user_info;
81061da546Spatrick char user_buffer[PATH_MAX];
82061da546Spatrick size_t user_buffer_size = sizeof(user_buffer);
83061da546Spatrick if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size,
84061da546Spatrick &user_info_ptr) == 0 &&
85061da546Spatrick user_info_ptr) {
86061da546Spatrick return PasswdEntry{user_info_ptr->pw_name, user_info_ptr->pw_shell};
87061da546Spatrick }
88061da546Spatrick #endif
89*f6aab3d8Srobert return std::nullopt;
90061da546Spatrick }
91061da546Spatrick
DoGetUserName(id_t uid)92*f6aab3d8Srobert std::optional<std::string> PosixUserIDResolver::DoGetUserName(id_t uid) {
93*f6aab3d8Srobert if (std::optional<PasswdEntry> password = GetPassword(uid))
94061da546Spatrick return password->username;
95*f6aab3d8Srobert return std::nullopt;
96061da546Spatrick }
97061da546Spatrick
DoGetGroupName(id_t gid)98*f6aab3d8Srobert std::optional<std::string> PosixUserIDResolver::DoGetGroupName(id_t gid) {
99061da546Spatrick #ifndef __ANDROID__
100061da546Spatrick char group_buffer[PATH_MAX];
101061da546Spatrick size_t group_buffer_size = sizeof(group_buffer);
102061da546Spatrick struct group group_info;
103061da546Spatrick struct group *group_info_ptr = &group_info;
104061da546Spatrick // Try the threadsafe version first
105061da546Spatrick if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size,
106061da546Spatrick &group_info_ptr) == 0) {
107061da546Spatrick if (group_info_ptr)
108061da546Spatrick return std::string(group_info_ptr->gr_name);
109061da546Spatrick } else {
110061da546Spatrick // The threadsafe version isn't currently working for me on darwin, but the
111061da546Spatrick // non-threadsafe version is, so I am calling it below.
112061da546Spatrick group_info_ptr = ::getgrgid(gid);
113061da546Spatrick if (group_info_ptr)
114061da546Spatrick return std::string(group_info_ptr->gr_name);
115061da546Spatrick }
116061da546Spatrick #endif
117*f6aab3d8Srobert return std::nullopt;
118061da546Spatrick }
119061da546Spatrick
120061da546Spatrick static llvm::ManagedStatic<PosixUserIDResolver> g_user_id_resolver;
121061da546Spatrick
GetUserIDResolver()122061da546Spatrick UserIDResolver &HostInfoPosix::GetUserIDResolver() {
123061da546Spatrick return *g_user_id_resolver;
124061da546Spatrick }
125061da546Spatrick
GetUserID()126061da546Spatrick uint32_t HostInfoPosix::GetUserID() { return getuid(); }
127061da546Spatrick
GetGroupID()128061da546Spatrick uint32_t HostInfoPosix::GetGroupID() { return getgid(); }
129061da546Spatrick
GetEffectiveUserID()130061da546Spatrick uint32_t HostInfoPosix::GetEffectiveUserID() { return geteuid(); }
131061da546Spatrick
GetEffectiveGroupID()132061da546Spatrick uint32_t HostInfoPosix::GetEffectiveGroupID() { return getegid(); }
133061da546Spatrick
GetDefaultShell()134061da546Spatrick FileSpec HostInfoPosix::GetDefaultShell() {
135061da546Spatrick if (const char *v = ::getenv("SHELL"))
136061da546Spatrick return FileSpec(v);
137*f6aab3d8Srobert if (std::optional<PasswdEntry> password = GetPassword(::geteuid()))
138061da546Spatrick return FileSpec(password->shell);
139061da546Spatrick return FileSpec("/bin/sh");
140061da546Spatrick }
141061da546Spatrick
ComputeSupportExeDirectory(FileSpec & file_spec)142061da546Spatrick bool HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec) {
143061da546Spatrick return ComputePathRelativeToLibrary(file_spec, "/bin");
144061da546Spatrick }
145061da546Spatrick
ComputeHeaderDirectory(FileSpec & file_spec)146061da546Spatrick bool HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec) {
147061da546Spatrick FileSpec temp_file("/opt/local/include/lldb");
148*f6aab3d8Srobert file_spec.SetDirectory(temp_file.GetPath());
149061da546Spatrick return true;
150061da546Spatrick }
151061da546Spatrick
GetEnvironmentVar(const std::string & var_name,std::string & var)152061da546Spatrick bool HostInfoPosix::GetEnvironmentVar(const std::string &var_name,
153061da546Spatrick std::string &var) {
154061da546Spatrick if (const char *pvar = ::getenv(var_name.c_str())) {
155061da546Spatrick var = std::string(pvar);
156061da546Spatrick return true;
157061da546Spatrick }
158061da546Spatrick return false;
159061da546Spatrick }
160