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