clang  16.0.0git
Distro.cpp
Go to the documentation of this file.
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/ADT/Triple.h"
15 #include "llvm/Support/ErrorOr.h"
16 #include "llvm/Support/Host.h"
17 #include "llvm/Support/MemoryBuffer.h"
18 #include "llvm/Support/Threading.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 
32  File.get()->getBuffer().split(Lines, "\n");
34 
35  // Obviously this can be improved a lot.
36  for (StringRef Line : Lines)
37  if (Version == Distro::UnknownDistro && Line.startswith("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 
58  File.get()->getBuffer().split(Lines, "\n");
60 
61  for (StringRef Line : Lines)
62  if (Version == Distro::UnknownDistro &&
63  Line.startswith("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  .Default(Distro::UnknownDistro);
97  return Version;
98 }
99 
100 static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
102 
103  // Newer freedesktop.org's compilant systemd-based systems
104  // should provide /etc/os-release or /usr/lib/os-release.
105  Version = DetectOsRelease(VFS);
106  if (Version != Distro::UnknownDistro)
107  return Version;
108 
109  // Older systems might provide /etc/lsb-release.
110  Version = DetectLsbRelease(VFS);
111  if (Version != Distro::UnknownDistro)
112  return Version;
113 
114  // Otherwise try some distro-specific quirks for RedHat...
115  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
116  VFS.getBufferForFile("/etc/redhat-release");
117 
118  if (File) {
119  StringRef Data = File.get()->getBuffer();
120  if (Data.startswith("Fedora release"))
121  return Distro::Fedora;
122  if (Data.startswith("Red Hat Enterprise Linux") ||
123  Data.startswith("CentOS") || Data.startswith("Scientific Linux")) {
124  if (Data.contains("release 7"))
125  return Distro::RHEL7;
126  else if (Data.contains("release 6"))
127  return Distro::RHEL6;
128  else if (Data.contains("release 5"))
129  return Distro::RHEL5;
130  }
131  return Distro::UnknownDistro;
132  }
133 
134  // ...for Debian
135  File = VFS.getBufferForFile("/etc/debian_version");
136  if (File) {
137  StringRef Data = File.get()->getBuffer();
138  // Contents: < major.minor > or < codename/sid >
139  int MajorVersion;
140  if (!Data.split('.').first.getAsInteger(10, MajorVersion)) {
141  switch (MajorVersion) {
142  case 5:
143  return Distro::DebianLenny;
144  case 6:
145  return Distro::DebianSqueeze;
146  case 7:
147  return Distro::DebianWheezy;
148  case 8:
149  return Distro::DebianJessie;
150  case 9:
151  return Distro::DebianStretch;
152  case 10:
153  return Distro::DebianBuster;
154  case 11:
155  return Distro::DebianBullseye;
156  case 12:
157  return Distro::DebianBookworm;
158  case 13:
159  return Distro::DebianTrixie;
160  default:
161  return Distro::UnknownDistro;
162  }
163  }
164  return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first)
165  .Case("squeeze/sid", Distro::DebianSqueeze)
166  .Case("wheezy/sid", Distro::DebianWheezy)
167  .Case("jessie/sid", Distro::DebianJessie)
168  .Case("stretch/sid", Distro::DebianStretch)
169  .Case("buster/sid", Distro::DebianBuster)
170  .Case("bullseye/sid", Distro::DebianBullseye)
171  .Case("bookworm/sid", Distro::DebianBookworm)
172  .Default(Distro::UnknownDistro);
173  }
174 
175  // ...for SUSE
176  File = VFS.getBufferForFile("/etc/SuSE-release");
177  if (File) {
178  StringRef Data = File.get()->getBuffer();
180  Data.split(Lines, "\n");
181  for (const StringRef &Line : Lines) {
182  if (!Line.trim().startswith("VERSION"))
183  continue;
184  std::pair<StringRef, StringRef> SplitLine = Line.split('=');
185  // Old versions have split VERSION and PATCHLEVEL
186  // Newer versions use VERSION = x.y
187  std::pair<StringRef, StringRef> SplitVer =
188  SplitLine.second.trim().split('.');
189  int Version;
190 
191  // OpenSUSE/SLES 10 and older are not supported and not compatible
192  // with our rules, so just treat them as Distro::UnknownDistro.
193  if (!SplitVer.first.getAsInteger(10, Version) && Version > 10)
194  return Distro::OpenSUSE;
195  return Distro::UnknownDistro;
196  }
197  return Distro::UnknownDistro;
198  }
199 
200  // ...and others.
201  if (VFS.exists("/etc/gentoo-release"))
202  return Distro::Gentoo;
203 
204  return Distro::UnknownDistro;
205 }
206 
207 static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS,
208  const llvm::Triple &TargetOrHost) {
209  // If we don't target Linux, no need to check the distro. This saves a few
210  // OS calls.
211  if (!TargetOrHost.isOSLinux())
212  return Distro::UnknownDistro;
213 
214  // True if we're backed by a real file system.
215  const bool onRealFS = (llvm::vfs::getRealFileSystem() == &VFS);
216 
217  // If the host is not running Linux, and we're backed by a real file
218  // system, no need to check the distro. This is the case where someone
219  // is cross-compiling from BSD or Windows to Linux, and it would be
220  // meaningless to try to figure out the "distro" of the non-Linux host.
221  llvm::Triple HostTriple(llvm::sys::getProcessTriple());
222  if (!HostTriple.isOSLinux() && onRealFS)
223  return Distro::UnknownDistro;
224 
225  if (onRealFS) {
226  // If we're backed by a real file system, perform
227  // the detection only once and save the result.
228  static Distro::DistroType LinuxDistro = DetectDistro(VFS);
229  return LinuxDistro;
230  }
231  // This is mostly for passing tests which uses llvm::vfs::InMemoryFileSystem,
232  // which is not "real".
233  return DetectDistro(VFS);
234 }
235 
236 Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)
237  : DistroVal(GetDistro(VFS, TargetOrHost)) {}
clang::driver::Distro::DebianLenny
@ DebianLenny
Definition: Distro.h:33
clang::driver::Distro::RHEL7
@ RHEL7
Definition: Distro.h:45
clang::driver::Distro::DebianStretch
@ DebianStretch
Definition: Distro.h:37
clang::driver::Distro::UbuntuHirsute
@ UbuntuHirsute
Definition: Distro.h:75
clang::driver::Distro::UbuntuVivid
@ UbuntuVivid
Definition: Distro.h:63
clang::DeclaratorContext::File
@ File
llvm::SmallVector< StringRef, 16 >
clang::driver::Distro::UbuntuTrusty
@ UbuntuTrusty
Definition: Distro.h:61
GetDistro
static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)
Definition: Distro.cpp:207
clang::driver::Distro::ArchLinux
@ ArchLinux
Definition: Distro.h:32
clang::driver::Distro::RHEL5
@ RHEL5
Definition: Distro.h:43
clang::driver::Distro::DebianJessie
@ DebianJessie
Definition: Distro.h:36
clang::driver::Distro::RHEL6
@ RHEL6
Definition: Distro.h:44
clang::driver::Distro::UbuntuGroovy
@ UbuntuGroovy
Definition: Distro.h:74
clang::driver::Distro::UbuntuXenial
@ UbuntuXenial
Definition: Distro.h:65
clang::driver::Distro::UbuntuDisco
@ UbuntuDisco
Definition: Distro.h:71
clang::driver::Distro::DebianBuster
@ DebianBuster
Definition: Distro.h:38
clang::driver::Distro::UbuntuLunar
@ UbuntuLunar
Definition: Distro.h:79
clang::driver::Distro::UbuntuSaucy
@ UbuntuSaucy
Definition: Distro.h:60
clang::driver::Distro::UbuntuMaverick
@ UbuntuMaverick
Definition: Distro.h:54
clang::driver::Distro::UbuntuIntrepid
@ UbuntuIntrepid
Definition: Distro.h:50
clang::driver::Distro::DistroType
DistroType
Definition: Distro.h:25
clang::driver::Distro::UbuntuEoan
@ UbuntuEoan
Definition: Distro.h:72
clang::driver::Distro::Fedora
@ Fedora
Definition: Distro.h:46
DetectDistro
static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS)
Definition: Distro.cpp:100
clang::driver::Distro::UbuntuQuantal
@ UbuntuQuantal
Definition: Distro.h:58
clang::driver::Distro::DebianBookworm
@ DebianBookworm
Definition: Distro.h:40
DetectLsbRelease
static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS)
Definition: Distro.cpp:51
Line
const AnnotatedLine * Line
Definition: UsingDeclarationsSorter.cpp:68
clang::driver::Distro::DebianSqueeze
@ DebianSqueeze
Definition: Distro.h:34
clang::driver::Distro::DebianTrixie
@ DebianTrixie
Definition: Distro.h:41
clang::driver::Distro::UbuntuWily
@ UbuntuWily
Definition: Distro.h:64
clang::driver::Distro::UbuntuLucid
@ UbuntuLucid
Definition: Distro.h:53
clang::driver::Distro::DebianWheezy
@ DebianWheezy
Definition: Distro.h:35
clang::driver::Distro::Exherbo
@ Exherbo
Definition: Distro.h:42
clang::driver::Distro::UbuntuBionic
@ UbuntuBionic
Definition: Distro.h:69
clang::driver::Distro::UbuntuPrecise
@ UbuntuPrecise
Definition: Distro.h:57
LLVM.h
clang::driver::Distro::UbuntuArtful
@ UbuntuArtful
Definition: Distro.h:68
clang::driver::Distro::UbuntuJammy
@ UbuntuJammy
Definition: Distro.h:77
clang::driver::Distro::UbuntuRaring
@ UbuntuRaring
Definition: Distro.h:59
clang::driver::Distro::UnknownDistro
@ UnknownDistro
Definition: Distro.h:80
clang::driver::Distro::UbuntuYakkety
@ UbuntuYakkety
Definition: Distro.h:66
DetectOsRelease
static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS)
Definition: Distro.cpp:23
clang
Definition: CalledOnceCheck.h:17
clang::driver::Distro::UbuntuKinetic
@ UbuntuKinetic
Definition: Distro.h:78
clang::driver::Distro::UbuntuZesty
@ UbuntuZesty
Definition: Distro.h:67
clang::driver::Distro::UbuntuImpish
@ UbuntuImpish
Definition: Distro.h:76
clang::driver::Distro::UbuntuNatty
@ UbuntuNatty
Definition: Distro.h:55
clang::driver::Distro::UbuntuUtopic
@ UbuntuUtopic
Definition: Distro.h:62
clang::driver::Distro::UbuntuHardy
@ UbuntuHardy
Definition: Distro.h:49
clang::driver::Distro::Distro
Distro()
Default constructor leaves the distribution unknown.
Definition: Distro.h:92
clang::driver::Distro::UbuntuFocal
@ UbuntuFocal
Definition: Distro.h:73
Distro.h
clang::driver
Definition: Action.h:31
clang::driver::Distro::OpenSUSE
@ OpenSUSE
Definition: Distro.h:48
clang::driver::Distro::UbuntuCosmic
@ UbuntuCosmic
Definition: Distro.h:70
clang::driver::Distro::AlpineLinux
@ AlpineLinux
Definition: Distro.h:31
clang::driver::Distro::UbuntuOneiric
@ UbuntuOneiric
Definition: Distro.h:56
clang::driver::Distro::UbuntuKarmic
@ UbuntuKarmic
Definition: Distro.h:52
clang::driver::Distro::UbuntuJaunty
@ UbuntuJaunty
Definition: Distro.h:51
clang::driver::Distro::DebianBullseye
@ DebianBullseye
Definition: Distro.h:39
clang::driver::Distro::Gentoo
@ Gentoo
Definition: Distro.h:47