Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Driver/Distro.cpp
35233 views
1
//===--- Distro.cpp - Linux distribution detection support ------*- 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 "clang/Driver/Distro.h"
10
#include "clang/Basic/LLVM.h"
11
#include "llvm/ADT/SmallVector.h"
12
#include "llvm/ADT/StringRef.h"
13
#include "llvm/ADT/StringSwitch.h"
14
#include "llvm/Support/ErrorOr.h"
15
#include "llvm/Support/MemoryBuffer.h"
16
#include "llvm/Support/Threading.h"
17
#include "llvm/TargetParser/Host.h"
18
#include "llvm/TargetParser/Triple.h"
19
20
using namespace clang::driver;
21
using namespace clang;
22
23
static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) {
24
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
25
VFS.getBufferForFile("/etc/os-release");
26
if (!File)
27
File = VFS.getBufferForFile("/usr/lib/os-release");
28
if (!File)
29
return Distro::UnknownDistro;
30
31
SmallVector<StringRef, 16> Lines;
32
File.get()->getBuffer().split(Lines, "\n");
33
Distro::DistroType Version = Distro::UnknownDistro;
34
35
// Obviously this can be improved a lot.
36
for (StringRef Line : Lines)
37
if (Version == Distro::UnknownDistro && Line.starts_with("ID="))
38
Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(3))
39
.Case("alpine", Distro::AlpineLinux)
40
.Case("fedora", Distro::Fedora)
41
.Case("gentoo", Distro::Gentoo)
42
.Case("arch", Distro::ArchLinux)
43
// On SLES, /etc/os-release was introduced in SLES 11.
44
.Case("sles", Distro::OpenSUSE)
45
.Case("opensuse", Distro::OpenSUSE)
46
.Case("exherbo", Distro::Exherbo)
47
.Default(Distro::UnknownDistro);
48
return Version;
49
}
50
51
static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) {
52
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
53
VFS.getBufferForFile("/etc/lsb-release");
54
if (!File)
55
return Distro::UnknownDistro;
56
57
SmallVector<StringRef, 16> Lines;
58
File.get()->getBuffer().split(Lines, "\n");
59
Distro::DistroType Version = Distro::UnknownDistro;
60
61
for (StringRef Line : Lines)
62
if (Version == Distro::UnknownDistro &&
63
Line.starts_with("DISTRIB_CODENAME="))
64
Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17))
65
.Case("hardy", Distro::UbuntuHardy)
66
.Case("intrepid", Distro::UbuntuIntrepid)
67
.Case("jaunty", Distro::UbuntuJaunty)
68
.Case("karmic", Distro::UbuntuKarmic)
69
.Case("lucid", Distro::UbuntuLucid)
70
.Case("maverick", Distro::UbuntuMaverick)
71
.Case("natty", Distro::UbuntuNatty)
72
.Case("oneiric", Distro::UbuntuOneiric)
73
.Case("precise", Distro::UbuntuPrecise)
74
.Case("quantal", Distro::UbuntuQuantal)
75
.Case("raring", Distro::UbuntuRaring)
76
.Case("saucy", Distro::UbuntuSaucy)
77
.Case("trusty", Distro::UbuntuTrusty)
78
.Case("utopic", Distro::UbuntuUtopic)
79
.Case("vivid", Distro::UbuntuVivid)
80
.Case("wily", Distro::UbuntuWily)
81
.Case("xenial", Distro::UbuntuXenial)
82
.Case("yakkety", Distro::UbuntuYakkety)
83
.Case("zesty", Distro::UbuntuZesty)
84
.Case("artful", Distro::UbuntuArtful)
85
.Case("bionic", Distro::UbuntuBionic)
86
.Case("cosmic", Distro::UbuntuCosmic)
87
.Case("disco", Distro::UbuntuDisco)
88
.Case("eoan", Distro::UbuntuEoan)
89
.Case("focal", Distro::UbuntuFocal)
90
.Case("groovy", Distro::UbuntuGroovy)
91
.Case("hirsute", Distro::UbuntuHirsute)
92
.Case("impish", Distro::UbuntuImpish)
93
.Case("jammy", Distro::UbuntuJammy)
94
.Case("kinetic", Distro::UbuntuKinetic)
95
.Case("lunar", Distro::UbuntuLunar)
96
.Case("mantic", Distro::UbuntuMantic)
97
.Case("noble", Distro::UbuntuNoble)
98
.Case("oracular", Distro::UbuntuOracular)
99
.Default(Distro::UnknownDistro);
100
return Version;
101
}
102
103
static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
104
Distro::DistroType Version = Distro::UnknownDistro;
105
106
// Newer freedesktop.org's compilant systemd-based systems
107
// should provide /etc/os-release or /usr/lib/os-release.
108
Version = DetectOsRelease(VFS);
109
if (Version != Distro::UnknownDistro)
110
return Version;
111
112
// Older systems might provide /etc/lsb-release.
113
Version = DetectLsbRelease(VFS);
114
if (Version != Distro::UnknownDistro)
115
return Version;
116
117
// Otherwise try some distro-specific quirks for Red Hat...
118
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
119
VFS.getBufferForFile("/etc/redhat-release");
120
121
if (File) {
122
StringRef Data = File.get()->getBuffer();
123
if (Data.starts_with("Fedora release"))
124
return Distro::Fedora;
125
if (Data.starts_with("Red Hat Enterprise Linux") ||
126
Data.starts_with("CentOS") || Data.starts_with("Scientific Linux")) {
127
if (Data.contains("release 7"))
128
return Distro::RHEL7;
129
else if (Data.contains("release 6"))
130
return Distro::RHEL6;
131
else if (Data.contains("release 5"))
132
return Distro::RHEL5;
133
}
134
return Distro::UnknownDistro;
135
}
136
137
// ...for Debian
138
File = VFS.getBufferForFile("/etc/debian_version");
139
if (File) {
140
StringRef Data = File.get()->getBuffer();
141
// Contents: < major.minor > or < codename/sid >
142
int MajorVersion;
143
if (!Data.split('.').first.getAsInteger(10, MajorVersion)) {
144
switch (MajorVersion) {
145
case 5:
146
return Distro::DebianLenny;
147
case 6:
148
return Distro::DebianSqueeze;
149
case 7:
150
return Distro::DebianWheezy;
151
case 8:
152
return Distro::DebianJessie;
153
case 9:
154
return Distro::DebianStretch;
155
case 10:
156
return Distro::DebianBuster;
157
case 11:
158
return Distro::DebianBullseye;
159
case 12:
160
return Distro::DebianBookworm;
161
case 13:
162
return Distro::DebianTrixie;
163
default:
164
return Distro::UnknownDistro;
165
}
166
}
167
return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first)
168
.Case("squeeze/sid", Distro::DebianSqueeze)
169
.Case("wheezy/sid", Distro::DebianWheezy)
170
.Case("jessie/sid", Distro::DebianJessie)
171
.Case("stretch/sid", Distro::DebianStretch)
172
.Case("buster/sid", Distro::DebianBuster)
173
.Case("bullseye/sid", Distro::DebianBullseye)
174
.Case("bookworm/sid", Distro::DebianBookworm)
175
.Case("trixie/sid", Distro::DebianTrixie)
176
.Default(Distro::UnknownDistro);
177
}
178
179
// ...for SUSE
180
File = VFS.getBufferForFile("/etc/SuSE-release");
181
if (File) {
182
StringRef Data = File.get()->getBuffer();
183
SmallVector<StringRef, 8> Lines;
184
Data.split(Lines, "\n");
185
for (const StringRef &Line : Lines) {
186
if (!Line.trim().starts_with("VERSION"))
187
continue;
188
std::pair<StringRef, StringRef> SplitLine = Line.split('=');
189
// Old versions have split VERSION and PATCHLEVEL
190
// Newer versions use VERSION = x.y
191
std::pair<StringRef, StringRef> SplitVer =
192
SplitLine.second.trim().split('.');
193
int Version;
194
195
// OpenSUSE/SLES 10 and older are not supported and not compatible
196
// with our rules, so just treat them as Distro::UnknownDistro.
197
if (!SplitVer.first.getAsInteger(10, Version) && Version > 10)
198
return Distro::OpenSUSE;
199
return Distro::UnknownDistro;
200
}
201
return Distro::UnknownDistro;
202
}
203
204
// ...and others.
205
if (VFS.exists("/etc/gentoo-release"))
206
return Distro::Gentoo;
207
208
return Distro::UnknownDistro;
209
}
210
211
static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS,
212
const llvm::Triple &TargetOrHost) {
213
// If we don't target Linux, no need to check the distro. This saves a few
214
// OS calls.
215
if (!TargetOrHost.isOSLinux())
216
return Distro::UnknownDistro;
217
218
// True if we're backed by a real file system.
219
const bool onRealFS = (llvm::vfs::getRealFileSystem() == &VFS);
220
221
// If the host is not running Linux, and we're backed by a real file
222
// system, no need to check the distro. This is the case where someone
223
// is cross-compiling from BSD or Windows to Linux, and it would be
224
// meaningless to try to figure out the "distro" of the non-Linux host.
225
llvm::Triple HostTriple(llvm::sys::getProcessTriple());
226
if (!HostTriple.isOSLinux() && onRealFS)
227
return Distro::UnknownDistro;
228
229
if (onRealFS) {
230
// If we're backed by a real file system, perform
231
// the detection only once and save the result.
232
static Distro::DistroType LinuxDistro = DetectDistro(VFS);
233
return LinuxDistro;
234
}
235
// This is mostly for passing tests which uses llvm::vfs::InMemoryFileSystem,
236
// which is not "real".
237
return DetectDistro(VFS);
238
}
239
240
Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)
241
: DistroVal(GetDistro(VFS, TargetOrHost)) {}
242
243