197a14e60SZachary Turner //===-- HostInfoLinux.cpp ---------------------------------------*- C++ -*-===// 297a14e60SZachary Turner // 397a14e60SZachary Turner // The LLVM Compiler Infrastructure 497a14e60SZachary Turner // 597a14e60SZachary Turner // This file is distributed under the University of Illinois Open Source 697a14e60SZachary Turner // License. See LICENSE.TXT for details. 797a14e60SZachary Turner // 897a14e60SZachary Turner //===----------------------------------------------------------------------===// 997a14e60SZachary Turner 1097a14e60SZachary Turner #include "lldb/Core/Log.h" 1197a14e60SZachary Turner #include "lldb/Host/linux/HostInfoLinux.h" 1297a14e60SZachary Turner 13*e47ffc3bSZachary Turner #include <limits.h> 1497a14e60SZachary Turner #include <stdio.h> 1597a14e60SZachary Turner #include <string.h> 1697a14e60SZachary Turner #include <sys/utsname.h> 1797a14e60SZachary Turner 1897a14e60SZachary Turner #include <algorithm> 1997a14e60SZachary Turner 2097a14e60SZachary Turner using namespace lldb_private; 2197a14e60SZachary Turner 22673b6e4fSZachary Turner namespace 23673b6e4fSZachary Turner { 24673b6e4fSZachary Turner struct HostInfoLinuxFields 25673b6e4fSZachary Turner { 26673b6e4fSZachary Turner HostInfoLinuxFields() 27673b6e4fSZachary Turner : m_os_major(0) 28673b6e4fSZachary Turner , m_os_minor(0) 29673b6e4fSZachary Turner , m_os_update(0) 30673b6e4fSZachary Turner { 31673b6e4fSZachary Turner } 32673b6e4fSZachary Turner 33673b6e4fSZachary Turner std::string m_distribution_id; 34673b6e4fSZachary Turner uint32_t m_os_major; 35673b6e4fSZachary Turner uint32_t m_os_minor; 36673b6e4fSZachary Turner uint32_t m_os_update; 37673b6e4fSZachary Turner }; 38673b6e4fSZachary Turner 39673b6e4fSZachary Turner HostInfoLinuxFields *g_fields = nullptr; 40673b6e4fSZachary Turner } 41673b6e4fSZachary Turner 42673b6e4fSZachary Turner void 43673b6e4fSZachary Turner HostInfoLinux::Initialize() 44673b6e4fSZachary Turner { 45673b6e4fSZachary Turner HostInfoPosix::Initialize(); 46673b6e4fSZachary Turner 47673b6e4fSZachary Turner g_fields = new HostInfoLinuxFields(); 48673b6e4fSZachary Turner } 4997a14e60SZachary Turner 5097a14e60SZachary Turner bool 5197a14e60SZachary Turner HostInfoLinux::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update) 5297a14e60SZachary Turner { 5397a14e60SZachary Turner static bool is_initialized = false; 5497a14e60SZachary Turner static bool success = false; 5597a14e60SZachary Turner 5697a14e60SZachary Turner if (!is_initialized) 5797a14e60SZachary Turner { 5897a14e60SZachary Turner is_initialized = true; 5997a14e60SZachary Turner struct utsname un; 6097a14e60SZachary Turner 6197a14e60SZachary Turner if (uname(&un)) 6297a14e60SZachary Turner goto finished; 6397a14e60SZachary Turner 64673b6e4fSZachary Turner int status = sscanf(un.release, "%u.%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor, &g_fields->m_os_update); 6597a14e60SZachary Turner if (status == 3) 6697a14e60SZachary Turner { 6797a14e60SZachary Turner success = true; 6897a14e60SZachary Turner goto finished; 6997a14e60SZachary Turner } 7097a14e60SZachary Turner 7197a14e60SZachary Turner // Some kernels omit the update version, so try looking for just "X.Y" and 7297a14e60SZachary Turner // set update to 0. 73673b6e4fSZachary Turner g_fields->m_os_update = 0; 74673b6e4fSZachary Turner status = sscanf(un.release, "%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor); 7597a14e60SZachary Turner success = !!(status == 2); 7697a14e60SZachary Turner } 7797a14e60SZachary Turner 7897a14e60SZachary Turner finished: 79673b6e4fSZachary Turner major = g_fields->m_os_major; 80673b6e4fSZachary Turner minor = g_fields->m_os_minor; 81673b6e4fSZachary Turner update = g_fields->m_os_update; 8297a14e60SZachary Turner return success; 8397a14e60SZachary Turner } 8497a14e60SZachary Turner 8597a14e60SZachary Turner llvm::StringRef 8697a14e60SZachary Turner HostInfoLinux::GetDistributionId() 8797a14e60SZachary Turner { 8897a14e60SZachary Turner static bool is_initialized = false; 8997a14e60SZachary Turner // Try to run 'lbs_release -i', and use that response 9097a14e60SZachary Turner // for the distribution id. 9197a14e60SZachary Turner 9297a14e60SZachary Turner if (!is_initialized) 9397a14e60SZachary Turner { 9497a14e60SZachary Turner is_initialized = true; 9597a14e60SZachary Turner 9697a14e60SZachary Turner Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST)); 9797a14e60SZachary Turner if (log) 9897a14e60SZachary Turner log->Printf("attempting to determine Linux distribution..."); 9997a14e60SZachary Turner 10097a14e60SZachary Turner // check if the lsb_release command exists at one of the 10197a14e60SZachary Turner // following paths 10297a14e60SZachary Turner const char *const exe_paths[] = {"/bin/lsb_release", "/usr/bin/lsb_release"}; 10397a14e60SZachary Turner 10497a14e60SZachary Turner for (size_t exe_index = 0; exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) 10597a14e60SZachary Turner { 10697a14e60SZachary Turner const char *const get_distribution_info_exe = exe_paths[exe_index]; 10797a14e60SZachary Turner if (access(get_distribution_info_exe, F_OK)) 10897a14e60SZachary Turner { 10997a14e60SZachary Turner // this exe doesn't exist, move on to next exe 11097a14e60SZachary Turner if (log) 11197a14e60SZachary Turner log->Printf("executable doesn't exist: %s", get_distribution_info_exe); 11297a14e60SZachary Turner continue; 11397a14e60SZachary Turner } 11497a14e60SZachary Turner 11597a14e60SZachary Turner // execute the distribution-retrieval command, read output 11697a14e60SZachary Turner std::string get_distribution_id_command(get_distribution_info_exe); 11797a14e60SZachary Turner get_distribution_id_command += " -i"; 11897a14e60SZachary Turner 11997a14e60SZachary Turner FILE *file = popen(get_distribution_id_command.c_str(), "r"); 12097a14e60SZachary Turner if (!file) 12197a14e60SZachary Turner { 12297a14e60SZachary Turner if (log) 12397a14e60SZachary Turner log->Printf("failed to run command: \"%s\", cannot retrieve " 12497a14e60SZachary Turner "platform information", 12597a14e60SZachary Turner get_distribution_id_command.c_str()); 12697a14e60SZachary Turner break; 12797a14e60SZachary Turner } 12897a14e60SZachary Turner 12997a14e60SZachary Turner // retrieve the distribution id string. 13097a14e60SZachary Turner char distribution_id[256] = {'\0'}; 13197a14e60SZachary Turner if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != NULL) 13297a14e60SZachary Turner { 13397a14e60SZachary Turner if (log) 13497a14e60SZachary Turner log->Printf("distribution id command returned \"%s\"", distribution_id); 13597a14e60SZachary Turner 13697a14e60SZachary Turner const char *const distributor_id_key = "Distributor ID:\t"; 13797a14e60SZachary Turner if (strstr(distribution_id, distributor_id_key)) 13897a14e60SZachary Turner { 13997a14e60SZachary Turner // strip newlines 14097a14e60SZachary Turner std::string id_string(distribution_id + strlen(distributor_id_key)); 14197a14e60SZachary Turner id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), id_string.end()); 14297a14e60SZachary Turner 14397a14e60SZachary Turner // lower case it and convert whitespace to underscores 14497a14e60SZachary Turner std::transform(id_string.begin(), id_string.end(), id_string.begin(), [](char ch) 14597a14e60SZachary Turner { 14697a14e60SZachary Turner return tolower(isspace(ch) ? '_' : ch); 14797a14e60SZachary Turner }); 14897a14e60SZachary Turner 149673b6e4fSZachary Turner g_fields->m_distribution_id = id_string; 15097a14e60SZachary Turner if (log) 151673b6e4fSZachary Turner log->Printf("distribution id set to \"%s\"", g_fields->m_distribution_id.c_str()); 15297a14e60SZachary Turner } 15397a14e60SZachary Turner else 15497a14e60SZachary Turner { 15597a14e60SZachary Turner if (log) 15697a14e60SZachary Turner log->Printf("failed to find \"%s\" field in \"%s\"", distributor_id_key, distribution_id); 15797a14e60SZachary Turner } 15897a14e60SZachary Turner } 15997a14e60SZachary Turner else 16097a14e60SZachary Turner { 16197a14e60SZachary Turner if (log) 16297a14e60SZachary Turner log->Printf("failed to retrieve distribution id, \"%s\" returned no" 16397a14e60SZachary Turner " lines", 16497a14e60SZachary Turner get_distribution_id_command.c_str()); 16597a14e60SZachary Turner } 16697a14e60SZachary Turner 16797a14e60SZachary Turner // clean up the file 16897a14e60SZachary Turner pclose(file); 16997a14e60SZachary Turner } 17097a14e60SZachary Turner } 17197a14e60SZachary Turner 172673b6e4fSZachary Turner return g_fields->m_distribution_id.c_str(); 17397a14e60SZachary Turner } 17413b18261SZachary Turner 17542ff0ad8SZachary Turner bool 17642ff0ad8SZachary Turner HostInfoLinux::ComputeSystemPluginsDirectory(FileSpec &file_spec) 17742ff0ad8SZachary Turner { 17842ff0ad8SZachary Turner file_spec.SetFile("/usr/lib/lldb", true); 17942ff0ad8SZachary Turner return true; 18042ff0ad8SZachary Turner } 18142ff0ad8SZachary Turner 18242ff0ad8SZachary Turner bool 18342ff0ad8SZachary Turner HostInfoLinux::ComputeUserPluginsDirectory(FileSpec &file_spec) 18442ff0ad8SZachary Turner { 18542ff0ad8SZachary Turner // XDG Base Directory Specification 18642ff0ad8SZachary Turner // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html 18742ff0ad8SZachary Turner // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. 18842ff0ad8SZachary Turner FileSpec lldb_file_spec; 18942ff0ad8SZachary Turner const char *xdg_data_home = getenv("XDG_DATA_HOME"); 19042ff0ad8SZachary Turner if (xdg_data_home && xdg_data_home[0]) 19142ff0ad8SZachary Turner { 19242ff0ad8SZachary Turner std::string user_plugin_dir(xdg_data_home); 19342ff0ad8SZachary Turner user_plugin_dir += "/lldb"; 19442ff0ad8SZachary Turner lldb_file_spec.SetFile(user_plugin_dir.c_str(), true); 19542ff0ad8SZachary Turner } 19642ff0ad8SZachary Turner else 19742ff0ad8SZachary Turner lldb_file_spec.SetFile("~/.local/share/lldb", true); 19842ff0ad8SZachary Turner 19942ff0ad8SZachary Turner return true; 20042ff0ad8SZachary Turner } 20142ff0ad8SZachary Turner 20213b18261SZachary Turner void 20313b18261SZachary Turner HostInfoLinux::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) 20413b18261SZachary Turner { 20513b18261SZachary Turner HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); 20613b18261SZachary Turner 20713b18261SZachary Turner const char *distribution_id = GetDistributionId().data(); 20813b18261SZachary Turner 20913b18261SZachary Turner // On Linux, "unknown" in the vendor slot isn't what we want for the default 21013b18261SZachary Turner // triple. It's probably an artifact of config.guess. 21113b18261SZachary Turner if (arch_32.IsValid()) 21213b18261SZachary Turner { 21313b18261SZachary Turner arch_32.SetDistributionId(distribution_id); 21413b18261SZachary Turner if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) 21513b18261SZachary Turner arch_32.GetTriple().setVendorName(""); 21613b18261SZachary Turner } 21713b18261SZachary Turner if (arch_64.IsValid()) 21813b18261SZachary Turner { 21913b18261SZachary Turner arch_64.SetDistributionId(distribution_id); 22013b18261SZachary Turner if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) 22113b18261SZachary Turner arch_64.GetTriple().setVendorName(""); 22213b18261SZachary Turner } 22313b18261SZachary Turner } 224