1 //===-- HostInfoPosix.cpp ---------------------------------------*- C++ -*-===// 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/Utility/Log.h" 11 #include "lldb/Utility/UserIDResolver.h" 12 13 #include "llvm/ADT/SmallString.h" 14 #include "llvm/ADT/Twine.h" 15 #include "llvm/Support/Path.h" 16 #include "llvm/Support/raw_ostream.h" 17 18 #include <grp.h> 19 #include <limits.h> 20 #include <mutex> 21 #include <pwd.h> 22 #include <stdlib.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 using namespace lldb_private; 27 28 size_t HostInfoPosix::GetPageSize() { return ::getpagesize(); } 29 30 bool HostInfoPosix::GetHostname(std::string &s) { 31 char hostname[PATH_MAX]; 32 hostname[sizeof(hostname) - 1] = '\0'; 33 if (::gethostname(hostname, sizeof(hostname) - 1) == 0) { 34 s.assign(hostname); 35 return true; 36 } 37 return false; 38 } 39 40 #ifdef __ANDROID__ 41 #include <android/api-level.h> 42 #endif 43 #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 44 #define USE_GETPWUID 45 #endif 46 47 namespace { 48 class PosixUserIDResolver : public UserIDResolver { 49 protected: 50 llvm::Optional<std::string> DoGetUserName(id_t uid) override; 51 llvm::Optional<std::string> DoGetGroupName(id_t gid) override; 52 }; 53 } // namespace 54 55 struct PasswdEntry { 56 std::string username; 57 std::string shell; 58 }; 59 60 static llvm::Optional<PasswdEntry> GetPassword(id_t uid) { 61 #ifdef USE_GETPWUID 62 // getpwuid_r is missing from android-9 63 // The caller should provide some thread safety by making sure no one calls 64 // this function concurrently, because using getpwuid is ultimately not 65 // thread-safe as we don't know who else might be calling it. 66 if (auto *user_info_ptr = ::getpwuid(uid)) 67 return PasswdEntry{user_info_ptr->pw_name, user_info_ptr->pw_shell}; 68 #else 69 struct passwd user_info; 70 struct passwd *user_info_ptr = &user_info; 71 char user_buffer[PATH_MAX]; 72 size_t user_buffer_size = sizeof(user_buffer); 73 if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size, 74 &user_info_ptr) == 0 && 75 user_info_ptr) { 76 return PasswdEntry{user_info_ptr->pw_name, user_info_ptr->pw_shell}; 77 } 78 #endif 79 return llvm::None; 80 } 81 82 llvm::Optional<std::string> PosixUserIDResolver::DoGetUserName(id_t uid) { 83 if (llvm::Optional<PasswdEntry> password = GetPassword(uid)) 84 return password->username; 85 return llvm::None; 86 } 87 88 llvm::Optional<std::string> PosixUserIDResolver::DoGetGroupName(id_t gid) { 89 #ifndef __ANDROID__ 90 char group_buffer[PATH_MAX]; 91 size_t group_buffer_size = sizeof(group_buffer); 92 struct group group_info; 93 struct group *group_info_ptr = &group_info; 94 // Try the threadsafe version first 95 if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size, 96 &group_info_ptr) == 0) { 97 if (group_info_ptr) 98 return std::string(group_info_ptr->gr_name); 99 } else { 100 // The threadsafe version isn't currently working for me on darwin, but the 101 // non-threadsafe version is, so I am calling it below. 102 group_info_ptr = ::getgrgid(gid); 103 if (group_info_ptr) 104 return std::string(group_info_ptr->gr_name); 105 } 106 #endif 107 return llvm::None; 108 } 109 110 static llvm::ManagedStatic<PosixUserIDResolver> g_user_id_resolver; 111 112 UserIDResolver &HostInfoPosix::GetUserIDResolver() { 113 return *g_user_id_resolver; 114 } 115 116 uint32_t HostInfoPosix::GetUserID() { return getuid(); } 117 118 uint32_t HostInfoPosix::GetGroupID() { return getgid(); } 119 120 uint32_t HostInfoPosix::GetEffectiveUserID() { return geteuid(); } 121 122 uint32_t HostInfoPosix::GetEffectiveGroupID() { return getegid(); } 123 124 FileSpec HostInfoPosix::GetDefaultShell() { 125 if (const char *v = ::getenv("SHELL")) 126 return FileSpec(v); 127 if (llvm::Optional<PasswdEntry> password = GetPassword(::geteuid())) 128 return FileSpec(password->shell); 129 return FileSpec("/bin/sh"); 130 } 131 132 bool HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec) { 133 return ComputePathRelativeToLibrary(file_spec, "/bin"); 134 } 135 136 bool HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec) { 137 FileSpec temp_file("/opt/local/include/lldb"); 138 file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str()); 139 return true; 140 } 141 142 bool HostInfoPosix::GetEnvironmentVar(const std::string &var_name, 143 std::string &var) { 144 if (const char *pvar = ::getenv(var_name.c_str())) { 145 var = std::string(pvar); 146 return true; 147 } 148 return false; 149 } 150