clang  15.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  .Default(Distro::UnknownDistro);
95  return Version;
96 }
97 
98 static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
100 
101  // Newer freedesktop.org's compilant systemd-based systems
102  // should provide /etc/os-release or /usr/lib/os-release.
103  Version = DetectOsRelease(VFS);
104  if (Version != Distro::UnknownDistro)
105  return Version;
106 
107  // Older systems might provide /etc/lsb-release.
108  Version = DetectLsbRelease(VFS);
109  if (Version != Distro::UnknownDistro)
110  return Version;
111 
112  // Otherwise try some distro-specific quirks for RedHat...
113  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
114  VFS.getBufferForFile("/etc/redhat-release");
115 
116  if (File) {
117  StringRef Data = File.get()->getBuffer();
118  if (Data.startswith("Fedora release"))
119  return Distro::Fedora;
120  if (Data.startswith("Red Hat Enterprise Linux") ||
121  Data.startswith("CentOS") || Data.startswith("Scientific Linux")) {
122  if (Data.contains("release 7"))
123  return Distro::RHEL7;
124  else if (Data.contains("release 6"))
125  return Distro::RHEL6;
126  else if (Data.contains("release 5"))
127  return Distro::RHEL5;
128  }
129  return Distro::UnknownDistro;
130  }
131 
132  // ...for Debian
133  File = VFS.getBufferForFile("/etc/debian_version");
134  if (File) {
135  StringRef Data = File.get()->getBuffer();
136  // Contents: < major.minor > or < codename/sid >
137  int MajorVersion;
138  if (!Data.split('.').first.getAsInteger(10, MajorVersion)) {
139  switch (MajorVersion) {
140  case 5:
141  return Distro::DebianLenny;
142  case 6:
143  return Distro::DebianSqueeze;
144  case 7:
145  return Distro::DebianWheezy;
146  case 8:
147  return Distro::DebianJessie;
148  case 9:
149  return Distro::DebianStretch;
150  case 10:
151  return Distro::DebianBuster;
152  case 11:
153  return Distro::DebianBullseye;
154  case 12:
155  return Distro::DebianBookworm;
156  default:
157  return Distro::UnknownDistro;
158  }
159  }
160  return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first)
161  .Case("squeeze/sid", Distro::DebianSqueeze)
162  .Case("wheezy/sid", Distro::DebianWheezy)
163  .Case("jessie/sid", Distro::DebianJessie)
164  .Case("stretch/sid", Distro::DebianStretch)
165  .Case("buster/sid", Distro::DebianBuster)
166  .Case("bullseye/sid", Distro::DebianBullseye)
167  .Case("bookworm/sid", Distro::DebianBookworm)
168  .Default(Distro::UnknownDistro);
169  }
170 
171  // ...for SUSE
172  File = VFS.getBufferForFile("/etc/SuSE-release");
173  if (File) {
174  StringRef Data = File.get()->getBuffer();
176  Data.split(Lines, "\n");
177  for (const StringRef &Line : Lines) {
178  if (!Line.trim().startswith("VERSION"))
179  continue;
180  std::pair<StringRef, StringRef> SplitLine = Line.split('=');
181  // Old versions have split VERSION and PATCHLEVEL
182  // Newer versions use VERSION = x.y
183  std::pair<StringRef, StringRef> SplitVer =
184  SplitLine.second.trim().split('.');
185  int Version;
186 
187  // OpenSUSE/SLES 10 and older are not supported and not compatible
188  // with our rules, so just treat them as Distro::UnknownDistro.
189  if (!SplitVer.first.getAsInteger(10, Version) && Version > 10)
190  return Distro::OpenSUSE;
191  return Distro::UnknownDistro;
192  }
193  return Distro::UnknownDistro;
194  }
195 
196  // ...and others.
197  if (VFS.exists("/etc/gentoo-release"))
198  return Distro::Gentoo;
199 
200  return Distro::UnknownDistro;
201 }
202 
203 static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS,
204  const llvm::Triple &TargetOrHost) {
205  // If we don't target Linux, no need to check the distro. This saves a few
206  // OS calls.
207  if (!TargetOrHost.isOSLinux())
208  return Distro::UnknownDistro;
209 
210  // True if we're backed by a real file system.
211  const bool onRealFS = (llvm::vfs::getRealFileSystem() == &VFS);
212 
213  // If the host is not running Linux, and we're backed by a real file
214  // system, no need to check the distro. This is the case where someone
215  // is cross-compiling from BSD or Windows to Linux, and it would be
216  // meaningless to try to figure out the "distro" of the non-Linux host.
217  llvm::Triple HostTriple(llvm::sys::getProcessTriple());
218  if (!HostTriple.isOSLinux() && onRealFS)
219  return Distro::UnknownDistro;
220 
221  if (onRealFS) {
222  // If we're backed by a real file system, perform
223  // the detection only once and save the result.
224  static Distro::DistroType LinuxDistro = DetectDistro(VFS);
225  return LinuxDistro;
226  }
227  // This is mostly for passing tests which uses llvm::vfs::InMemoryFileSystem,
228  // which is not "real".
229  return DetectDistro(VFS);
230 }
231 
232 Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)
233  : 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:203
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:98
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::UbuntuJammy
@ UbuntuJammy
Definition: Distro.h:76
clang::driver::Distro::UbuntuRaring
@ UbuntuRaring
Definition: Distro.h:58
clang::driver::Distro::UnknownDistro
@ UnknownDistro
Definition: Distro.h:77
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:89
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