blob: 12885756e2b2346146aa8d729d1fb4bf8b5f7655 [file] [log] [blame]
Zachary Turner97a14e62014-08-19 17:18:29 +00001//===-- HostInfoLinux.cpp ---------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Zachary Turner97a14e62014-08-19 17:18:29 +000010#include "lldb/Host/linux/HostInfoLinux.h"
Jonas Devlieghere60cf3f82018-11-01 17:35:31 +000011#include "lldb/Host/Config.h"
12#include "lldb/Host/FileSystem.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000013#include "lldb/Utility/Log.h"
Zachary Turner97a14e62014-08-19 17:18:29 +000014
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +000015#include "llvm/Support/Threading.h"
16
Zachary Turnere47ffc32014-08-21 21:02:47 +000017#include <limits.h>
Zachary Turner97a14e62014-08-19 17:18:29 +000018#include <stdio.h>
19#include <string.h>
20#include <sys/utsname.h>
Pavel Labathb6dbe9a2017-07-18 13:14:01 +000021#include <unistd.h>
Zachary Turner97a14e62014-08-19 17:18:29 +000022
23#include <algorithm>
Greg Claytonff48e4b2015-02-03 02:05:44 +000024#include <mutex> // std::once
Zachary Turner97a14e62014-08-19 17:18:29 +000025
26using namespace lldb_private;
27
Kate Stoneb9c1b512016-09-06 20:57:50 +000028namespace {
29struct HostInfoLinuxFields {
Kate Stoneb9c1b512016-09-06 20:57:50 +000030 std::string m_distribution_id;
Pavel Labath2272c482018-06-18 15:02:23 +000031 llvm::VersionTuple m_os_version;
Zachary Turner673b6e42014-08-21 17:57:03 +000032};
33
34HostInfoLinuxFields *g_fields = nullptr;
35}
36
Kate Stoneb9c1b512016-09-06 20:57:50 +000037void HostInfoLinux::Initialize() {
38 HostInfoPosix::Initialize();
Zachary Turner673b6e42014-08-21 17:57:03 +000039
Kate Stoneb9c1b512016-09-06 20:57:50 +000040 g_fields = new HostInfoLinuxFields();
Zachary Turner673b6e42014-08-21 17:57:03 +000041}
Zachary Turner97a14e62014-08-19 17:18:29 +000042
Pavel Labath2272c482018-06-18 15:02:23 +000043llvm::VersionTuple HostInfoLinux::GetOSVersion() {
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +000044 static llvm::once_flag g_once_flag;
45 llvm::call_once(g_once_flag, []() {
Oleksiy Vyalov53c038a2014-12-09 02:13:05 +000046 struct utsname un;
Pavel Labath2272c482018-06-18 15:02:23 +000047 if (uname(&un) != 0)
48 return;
49
50 llvm::StringRef release = un.release;
51 // The kernel release string can include a lot of stuff (e.g.
52 // 4.9.0-6-amd64). We're only interested in the numbered prefix.
53 release = release.substr(0, release.find_first_not_of("0123456789."));
54 g_fields->m_os_version.tryParse(release);
Kate Stoneb9c1b512016-09-06 20:57:50 +000055 });
Oleksiy Vyalov53c038a2014-12-09 02:13:05 +000056
Pavel Labath2272c482018-06-18 15:02:23 +000057 return g_fields->m_os_version;
Oleksiy Vyalov53c038a2014-12-09 02:13:05 +000058}
59
Kate Stoneb9c1b512016-09-06 20:57:50 +000060bool HostInfoLinux::GetOSBuildString(std::string &s) {
61 struct utsname un;
62 ::memset(&un, 0, sizeof(utsname));
63 s.clear();
Oleksiy Vyalov53c038a2014-12-09 02:13:05 +000064
Kate Stoneb9c1b512016-09-06 20:57:50 +000065 if (uname(&un) < 0)
66 return false;
Oleksiy Vyalov53c038a2014-12-09 02:13:05 +000067
Kate Stoneb9c1b512016-09-06 20:57:50 +000068 s.assign(un.release);
69 return true;
Oleksiy Vyalov53c038a2014-12-09 02:13:05 +000070}
71
Kate Stoneb9c1b512016-09-06 20:57:50 +000072bool HostInfoLinux::GetOSKernelDescription(std::string &s) {
73 struct utsname un;
Zachary Turner97a14e62014-08-19 17:18:29 +000074
Kate Stoneb9c1b512016-09-06 20:57:50 +000075 ::memset(&un, 0, sizeof(utsname));
76 s.clear();
77
78 if (uname(&un) < 0)
79 return false;
80
81 s.assign(un.version);
82 return true;
83}
84
85llvm::StringRef HostInfoLinux::GetDistributionId() {
Adrian Prantl05097242018-04-30 16:49:04 +000086 // Try to run 'lbs_release -i', and use that response for the distribution
87 // id.
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +000088 static llvm::once_flag g_once_flag;
89 llvm::call_once(g_once_flag, []() {
Kate Stoneb9c1b512016-09-06 20:57:50 +000090
91 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST));
92 if (log)
93 log->Printf("attempting to determine Linux distribution...");
94
Adrian Prantl05097242018-04-30 16:49:04 +000095 // check if the lsb_release command exists at one of the following paths
Kate Stoneb9c1b512016-09-06 20:57:50 +000096 const char *const exe_paths[] = {"/bin/lsb_release",
97 "/usr/bin/lsb_release"};
98
99 for (size_t exe_index = 0;
100 exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) {
101 const char *const get_distribution_info_exe = exe_paths[exe_index];
102 if (access(get_distribution_info_exe, F_OK)) {
103 // this exe doesn't exist, move on to next exe
Zachary Turner97a14e62014-08-19 17:18:29 +0000104 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105 log->Printf("executable doesn't exist: %s",
106 get_distribution_info_exe);
107 continue;
108 }
Zachary Turner97a14e62014-08-19 17:18:29 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 // execute the distribution-retrieval command, read output
111 std::string get_distribution_id_command(get_distribution_info_exe);
112 get_distribution_id_command += " -i";
Zachary Turner97a14e62014-08-19 17:18:29 +0000113
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114 FILE *file = popen(get_distribution_id_command.c_str(), "r");
115 if (!file) {
116 if (log)
117 log->Printf("failed to run command: \"%s\", cannot retrieve "
118 "platform information",
119 get_distribution_id_command.c_str());
120 break;
121 }
Zachary Turner97a14e62014-08-19 17:18:29 +0000122
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123 // retrieve the distribution id string.
124 char distribution_id[256] = {'\0'};
125 if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != NULL) {
126 if (log)
127 log->Printf("distribution id command returned \"%s\"",
128 distribution_id);
Zachary Turner97a14e62014-08-19 17:18:29 +0000129
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130 const char *const distributor_id_key = "Distributor ID:\t";
131 if (strstr(distribution_id, distributor_id_key)) {
132 // strip newlines
133 std::string id_string(distribution_id + strlen(distributor_id_key));
134 id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'),
135 id_string.end());
Zachary Turner97a14e62014-08-19 17:18:29 +0000136
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 // lower case it and convert whitespace to underscores
138 std::transform(
139 id_string.begin(), id_string.end(), id_string.begin(),
140 [](char ch) { return tolower(isspace(ch) ? '_' : ch); });
Zachary Turner97a14e62014-08-19 17:18:29 +0000141
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142 g_fields->m_distribution_id = id_string;
143 if (log)
144 log->Printf("distribution id set to \"%s\"",
145 g_fields->m_distribution_id.c_str());
146 } else {
147 if (log)
148 log->Printf("failed to find \"%s\" field in \"%s\"",
149 distributor_id_key, distribution_id);
Zachary Turner97a14e62014-08-19 17:18:29 +0000150 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000151 } else {
152 if (log)
153 log->Printf("failed to retrieve distribution id, \"%s\" returned no"
154 " lines",
155 get_distribution_id_command.c_str());
156 }
Zachary Turner97a14e62014-08-19 17:18:29 +0000157
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158 // clean up the file
159 pclose(file);
Zachary Turnera21fee02014-08-21 21:49:24 +0000160 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000161 });
Zachary Turnera21fee02014-08-21 21:49:24 +0000162
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000163 return g_fields->m_distribution_id;
Zachary Turnera21fee02014-08-21 21:49:24 +0000164}
165
Kate Stoneb9c1b512016-09-06 20:57:50 +0000166FileSpec HostInfoLinux::GetProgramFileSpec() {
167 static FileSpec g_program_filespec;
168
169 if (!g_program_filespec) {
170 char exe_path[PATH_MAX];
171 ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
172 if (len > 0) {
173 exe_path[len] = 0;
Jonas Devliegheredd2f78e2018-06-13 22:23:48 +0000174 g_program_filespec.SetFile(exe_path, false, FileSpec::Style::native);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175 }
176 }
177
178 return g_program_filespec;
Chaoren Linc30c49c2015-02-10 18:30:34 +0000179}
180
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181bool HostInfoLinux::ComputeSupportExeDirectory(FileSpec &file_spec) {
182 if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) &&
Jonas Devlieghere60cf3f82018-11-01 17:35:31 +0000183 file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec))
Zachary Turner42ff0ad2014-08-21 17:29:12 +0000184 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000185 file_spec.GetDirectory() = GetProgramFileSpec().GetDirectory();
186 return !file_spec.GetDirectory().IsEmpty();
Zachary Turner42ff0ad2014-08-21 17:29:12 +0000187}
188
Kate Stoneb9c1b512016-09-06 20:57:50 +0000189bool HostInfoLinux::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
Michal Gornyc0611752018-01-29 18:25:06 +0000190 FileSpec temp_file("/usr/lib" LLDB_LIBDIR_SUFFIX "/lldb/plugins", true);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191 file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
192 return true;
Zachary Turner42ff0ad2014-08-21 17:29:12 +0000193}
194
Kate Stoneb9c1b512016-09-06 20:57:50 +0000195bool HostInfoLinux::ComputeUserPluginsDirectory(FileSpec &file_spec) {
196 // XDG Base Directory Specification
Adrian Prantl05097242018-04-30 16:49:04 +0000197 // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If
198 // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000199 const char *xdg_data_home = getenv("XDG_DATA_HOME");
200 if (xdg_data_home && xdg_data_home[0]) {
201 std::string user_plugin_dir(xdg_data_home);
202 user_plugin_dir += "/lldb";
203 file_spec.GetDirectory().SetCString(user_plugin_dir.c_str());
204 } else
205 file_spec.GetDirectory().SetCString("~/.local/share/lldb");
206 return true;
207}
Zachary Turner13b18262014-08-20 16:42:51 +0000208
Kate Stoneb9c1b512016-09-06 20:57:50 +0000209void HostInfoLinux::ComputeHostArchitectureSupport(ArchSpec &arch_32,
210 ArchSpec &arch_64) {
211 HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64);
Zachary Turner13b18262014-08-20 16:42:51 +0000212
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213 const char *distribution_id = GetDistributionId().data();
214
215 // On Linux, "unknown" in the vendor slot isn't what we want for the default
216 // triple. It's probably an artifact of config.guess.
217 if (arch_32.IsValid()) {
218 arch_32.SetDistributionId(distribution_id);
219 if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor)
220 arch_32.GetTriple().setVendorName(llvm::StringRef());
221 }
222 if (arch_64.IsValid()) {
223 arch_64.SetDistributionId(distribution_id);
224 if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor)
225 arch_64.GetTriple().setVendorName(llvm::StringRef());
226 }
Zachary Turner13b18262014-08-20 16:42:51 +0000227}