blob: 8e620f43ca64af3b6f5029382527a6fcb9d0e4a9 [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
10#include "lldb/Core/Log.h"
11#include "lldb/Host/linux/HostInfoLinux.h"
12
13#include <stdio.h>
14#include <string.h>
15#include <sys/utsname.h>
16
17#include <algorithm>
18
19using namespace lldb_private;
20
21std::string HostInfoLinux::m_distribution_id;
22uint32_t HostInfoLinux::m_os_major = 0;
23uint32_t HostInfoLinux::m_os_minor = 0;
24uint32_t HostInfoLinux::m_os_update = 0;
25
26bool
27HostInfoLinux::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
28{
29 static bool is_initialized = false;
30 static bool success = false;
31
32 if (!is_initialized)
33 {
34 is_initialized = true;
35 struct utsname un;
36
37 if (uname(&un))
38 goto finished;
39
40 int status = sscanf(un.release, "%u.%u.%u", &major, &minor, &update);
41 if (status == 3)
42 {
43 success = true;
44 goto finished;
45 }
46
47 // Some kernels omit the update version, so try looking for just "X.Y" and
48 // set update to 0.
49 update = 0;
50 status = sscanf(un.release, "%u.%u", &major, &minor);
51 success = !!(status == 2);
52 }
53
54finished:
55 major = m_os_major;
56 minor = m_os_minor;
57 update = m_os_update;
58 return success;
59}
60
61llvm::StringRef
62HostInfoLinux::GetDistributionId()
63{
64 static bool is_initialized = false;
65 // Try to run 'lbs_release -i', and use that response
66 // for the distribution id.
67
68 if (!is_initialized)
69 {
70 is_initialized = true;
71
72 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST));
73 if (log)
74 log->Printf("attempting to determine Linux distribution...");
75
76 // check if the lsb_release command exists at one of the
77 // following paths
78 const char *const exe_paths[] = {"/bin/lsb_release", "/usr/bin/lsb_release"};
79
80 for (size_t exe_index = 0; exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index)
81 {
82 const char *const get_distribution_info_exe = exe_paths[exe_index];
83 if (access(get_distribution_info_exe, F_OK))
84 {
85 // this exe doesn't exist, move on to next exe
86 if (log)
87 log->Printf("executable doesn't exist: %s", get_distribution_info_exe);
88 continue;
89 }
90
91 // execute the distribution-retrieval command, read output
92 std::string get_distribution_id_command(get_distribution_info_exe);
93 get_distribution_id_command += " -i";
94
95 FILE *file = popen(get_distribution_id_command.c_str(), "r");
96 if (!file)
97 {
98 if (log)
99 log->Printf("failed to run command: \"%s\", cannot retrieve "
100 "platform information",
101 get_distribution_id_command.c_str());
102 break;
103 }
104
105 // retrieve the distribution id string.
106 char distribution_id[256] = {'\0'};
107 if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != NULL)
108 {
109 if (log)
110 log->Printf("distribution id command returned \"%s\"", distribution_id);
111
112 const char *const distributor_id_key = "Distributor ID:\t";
113 if (strstr(distribution_id, distributor_id_key))
114 {
115 // strip newlines
116 std::string id_string(distribution_id + strlen(distributor_id_key));
117 id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), id_string.end());
118
119 // lower case it and convert whitespace to underscores
120 std::transform(id_string.begin(), id_string.end(), id_string.begin(), [](char ch)
121 {
122 return tolower(isspace(ch) ? '_' : ch);
123 });
124
125 m_distribution_id = id_string;
126 if (log)
127 log->Printf("distribution id set to \"%s\"", m_distribution_id.c_str());
128 }
129 else
130 {
131 if (log)
132 log->Printf("failed to find \"%s\" field in \"%s\"", distributor_id_key, distribution_id);
133 }
134 }
135 else
136 {
137 if (log)
138 log->Printf("failed to retrieve distribution id, \"%s\" returned no"
139 " lines",
140 get_distribution_id_command.c_str());
141 }
142
143 // clean up the file
144 pclose(file);
145 }
146 }
147
148 return m_distribution_id.c_str();
149}