blob: b53b121c309a139cd49eac0084ad00e9b2befca9 [file] [log] [blame]
[email protected]46e9acad2012-06-13 23:20:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]75ae5422009-04-21 17:20:102// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]912c6452009-07-17 05:55:515#include "base/linux_util.h"
[email protected]75ae5422009-04-21 17:20:106
[email protected]85ebe8f2009-10-29 04:02:557#include <dirent.h>
8#include <errno.h>
[email protected]662183142010-07-16 19:28:179#include <fcntl.h>
avi9b6f42932015-12-26 22:15:1410#include <limits.h>
[email protected]75ae5422009-04-21 17:20:1011#include <stdlib.h>
[email protected]85ebe8f2009-10-29 04:02:5512#include <sys/stat.h>
[email protected]662183142010-07-16 19:28:1713#include <sys/types.h>
[email protected]85ebe8f2009-10-29 04:02:5514#include <unistd.h>
[email protected]75ae5422009-04-21 17:20:1015
Tomas Popela5b9b01f2019-09-10 19:42:3116#include <iomanip>
dcheng093de9b2016-04-04 21:25:5117#include <memory>
[email protected]912c6452009-07-17 05:55:5118
Alexandr Ilind4f4b342019-01-08 15:34:0919#include "base/files/dir_reader_posix.h"
[email protected]e3177dd52014-08-13 20:22:1420#include "base/files/file_util.h"
Lei Zhang3bf06692020-02-03 19:41:0521#include "base/files/scoped_file.h"
Alexandr Ilind4f4b342019-01-08 15:34:0922#include "base/strings/safe_sprintf.h"
reveman7b97c322016-09-20 02:10:5823#include "base/strings/string_number_conversions.h"
24#include "base/strings/string_split.h"
revemane5aece572017-09-04 07:18:3325#include "base/strings/string_tokenizer.h"
[email protected]d529cb02013-06-10 19:06:5726#include "base/strings/string_util.h"
avi9b6f42932015-12-26 22:15:1427#include "build/build_config.h"
Yuta Hijikata000df18f2020-11-18 06:55:5828#include "build/chromeos_buildflags.h"
[email protected]87fc1682009-07-22 00:22:4929
Tomas Popela5b9b01f2019-09-10 19:42:3130namespace base {
31
[email protected]87fc1682009-07-22 00:22:4932namespace {
33
Yuta Hijikata000df18f2020-11-18 06:55:5834#if !BUILDFLAG(IS_CHROMEOS_ASH)
Tomas Popela5b9b01f2019-09-10 19:42:3135std::string GetKeyValueFromOSReleaseFile(const std::string& input,
36 const char* key) {
37 StringPairs key_value_pairs;
38 SplitStringIntoKeyValuePairs(input, '=', '\n', &key_value_pairs);
39 for (const auto& pair : key_value_pairs) {
40 const std::string& key_str = pair.first;
41 const std::string& value_str = pair.second;
42 if (key_str == key) {
43 // It can contain quoted characters.
44 std::stringstream ss;
45 std::string pretty_name;
46 ss << value_str;
47 // Quoted with a single tick?
48 if (value_str[0] == '\'')
49 ss >> std::quoted(pretty_name, '\'');
50 else
51 ss >> std::quoted(pretty_name);
52
53 return pretty_name;
54 }
55 }
56
57 return "";
58}
59
60bool ReadDistroFromOSReleaseFile(const char* file) {
61 static const char kPrettyName[] = "PRETTY_NAME";
62
63 std::string os_release_content;
64 if (!ReadFileToString(FilePath(file), &os_release_content))
65 return false;
66
67 std::string pretty_name =
68 GetKeyValueFromOSReleaseFile(os_release_content, kPrettyName);
69 if (pretty_name.empty())
70 return false;
71
72 SetLinuxDistro(pretty_name);
73 return true;
74}
75
76// https://www.freedesktop.org/software/systemd/man/os-release.html
Tom Anderson02185a02020-02-01 03:49:2577class DistroNameGetter {
78 public:
79 DistroNameGetter() {
80 static const char* const kFilesToCheck[] = {"/etc/os-release",
81 "/usr/lib/os-release"};
82 for (const char* file : kFilesToCheck) {
83 if (ReadDistroFromOSReleaseFile(file))
84 return;
85 }
Tomas Popela5b9b01f2019-09-10 19:42:3186 }
Tom Anderson02185a02020-02-01 03:49:2587};
Yuta Hijikata000df18f2020-11-18 06:55:5888#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
[email protected]19467c02009-10-13 02:51:0789
[email protected]6dde9d72010-08-26 08:55:2290// Account for the terminating null character.
Lei Zhang3bf06692020-02-03 19:41:0591constexpr int kDistroSize = 128 + 1;
92
93} // namespace
[email protected]6dde9d72010-08-26 08:55:2294
[email protected]912c6452009-07-17 05:55:5195// We use this static string to hold the Linux distro info. If we
96// crash, the crash handler code will send this in the crash dump.
[email protected]6dde9d72010-08-26 08:55:2297char g_linux_distro[kDistroSize] =
Yuta Hijikata000df18f2020-11-18 06:55:5898#if BUILDFLAG(IS_CHROMEOS_ASH)
[email protected]78f6f512009-10-21 19:04:1799 "CrOS";
Xiaohan Wang38e4ebb2022-01-19 06:57:43100#elif BUILDFLAG(IS_ANDROID)
[email protected]84a1ab5a2012-07-18 01:49:22101 "Android";
Tom Anderson02185a02020-02-01 03:49:25102#else
[email protected]78f6f512009-10-21 19:04:17103 "Unknown";
104#endif
[email protected]912c6452009-07-17 05:55:51105
Raphael Kubo da Costa71c31f52019-09-11 16:17:00106// This function is only supposed to be used in tests. The declaration in the
107// header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
108// by tests but not non-test code. However, this .cc file is compiled as part
109// of "base" where "UNIT_TEST" is not defined. So we need to specify
110// "BASE_EXPORT" here again so that they are visible to tests.
Tomas Popela5b9b01f2019-09-10 19:42:31111BASE_EXPORT std::string GetKeyValueFromOSReleaseFileForTesting(
112 const std::string& input,
113 const char* key) {
Yuta Hijikata000df18f2020-11-18 06:55:58114#if !BUILDFLAG(IS_CHROMEOS_ASH)
Tomas Popela5b9b01f2019-09-10 19:42:31115 return GetKeyValueFromOSReleaseFile(input, key);
116#else
117 return "";
Yuta Hijikata000df18f2020-11-18 06:55:58118#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
Tomas Popela5b9b01f2019-09-10 19:42:31119}
120
[email protected]912c6452009-07-17 05:55:51121std::string GetLinuxDistro() {
Yuta Hijikata000df18f2020-11-18 06:55:58122#if !BUILDFLAG(IS_CHROMEOS_ASH)
[email protected]84a1ab5a2012-07-18 01:49:22123 // We do this check only once per process. If it fails, there's
Tomas Popela5b9b01f2019-09-10 19:42:31124 // little reason to believe it will work if we attempt to run it again.
Avi Drissmanded77172021-07-02 18:23:00125 static DistroNameGetter distro_name_getter;
[email protected]78f6f512009-10-21 19:04:17126#endif
Tom Anderson02185a02020-02-01 03:49:25127 return g_linux_distro;
[email protected]912c6452009-07-17 05:55:51128}
129
[email protected]6dde9d72010-08-26 08:55:22130void SetLinuxDistro(const std::string& distro) {
131 std::string trimmed_distro;
olli.raula36aa8be2015-09-10 11:14:22132 TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro);
133 strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
[email protected]6dde9d72010-08-26 08:55:22134}
135
Alexandr Ilind4f4b342019-01-08 15:34:09136bool GetThreadsForProcess(pid_t pid, std::vector<pid_t>* tids) {
137 // 25 > strlen("/proc//task") + strlen(std::to_string(INT_MAX)) + 1 = 22
138 char buf[25];
Tomas Popela5b9b01f2019-09-10 19:42:31139 strings::SafeSPrintf(buf, "/proc/%d/task", pid);
Alexandr Ilind4f4b342019-01-08 15:34:09140 DirReaderPosix dir_reader(buf);
141
142 if (!dir_reader.IsValid()) {
143 DLOG(WARNING) << "Cannot open " << buf;
144 return false;
145 }
146
147 while (dir_reader.Next()) {
148 char* endptr;
149 const unsigned long int tid_ul = strtoul(dir_reader.name(), &endptr, 10);
150 if (tid_ul == ULONG_MAX || *endptr)
151 continue;
152 tids->push_back(tid_ul);
153 }
154
155 return true;
156}
157
[email protected]cb7d53e2011-06-21 04:21:06158pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
159 bool* syscall_supported) {
Lei Zhang3bf06692020-02-03 19:41:05160 if (syscall_supported)
[email protected]cb7d53e2011-06-21 04:21:06161 *syscall_supported = false;
162
[email protected]662183142010-07-16 19:28:17163 std::vector<pid_t> tids;
Alexandr Ilind4f4b342019-01-08 15:34:09164 if (!GetThreadsForProcess(pid, &tids))
reveman7b97c322016-09-20 02:10:58165 return -1;
[email protected]662183142010-07-16 19:28:17166
Lei Zhang3bf06692020-02-03 19:41:05167 std::vector<char> syscall_data(expected_data.size());
reveman7b97c322016-09-20 02:10:58168 for (pid_t tid : tids) {
169 char buf[256];
170 snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, tid);
Lei Zhang3bf06692020-02-03 19:41:05171 ScopedFD fd(open(buf, O_RDONLY));
172 if (!fd.is_valid())
[email protected]662183142010-07-16 19:28:17173 continue;
174
Lei Zhang3bf06692020-02-03 19:41:05175 *syscall_supported = true;
176 if (!ReadFromFD(fd.get(), syscall_data.data(), syscall_data.size()))
177 continue;
178
179 if (0 == strncmp(expected_data.c_str(), syscall_data.data(),
180 expected_data.size())) {
reveman7b97c322016-09-20 02:10:58181 return tid;
182 }
183 }
184 return -1;
185}
186
187pid_t FindThreadID(pid_t pid, pid_t ns_tid, bool* ns_pid_supported) {
Lei Zhang3bf06692020-02-03 19:41:05188 *ns_pid_supported = false;
reveman7b97c322016-09-20 02:10:58189
190 std::vector<pid_t> tids;
Alexandr Ilind4f4b342019-01-08 15:34:09191 if (!GetThreadsForProcess(pid, &tids))
reveman7b97c322016-09-20 02:10:58192 return -1;
193
194 for (pid_t tid : tids) {
195 char buf[256];
196 snprintf(buf, sizeof(buf), "/proc/%d/task/%d/status", pid, tid);
197 std::string status;
198 if (!ReadFileToString(FilePath(buf), &status))
199 return -1;
revemane5aece572017-09-04 07:18:33200 StringTokenizer tokenizer(status, "\n");
201 while (tokenizer.GetNext()) {
202 StringPiece value_str(tokenizer.token_piece());
Jan Wilken Dörrief05bb102020-08-18 19:35:56203 if (!StartsWith(value_str, "NSpid"))
revemane5aece572017-09-04 07:18:33204 continue;
Lei Zhang3bf06692020-02-03 19:41:05205
206 *ns_pid_supported = true;
revemane5aece572017-09-04 07:18:33207 std::vector<StringPiece> split_value_str = SplitStringPiece(
208 value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
209 DCHECK_GE(split_value_str.size(), 2u);
210 int value;
211 // The last value in the list is the PID in the namespace.
212 if (StringToInt(split_value_str.back(), &value) && value == ns_tid) {
213 // The second value in the list is the real PID.
214 if (StringToInt(split_value_str[1], &value))
215 return value;
reveman7b97c322016-09-20 02:10:58216 }
revemane5aece572017-09-04 07:18:33217 break;
[email protected]662183142010-07-16 19:28:17218 }
219 }
220 return -1;
221}
222
[email protected]75ae5422009-04-21 17:20:10223} // namespace base