Path: blob/main/contrib/llvm-project/clang/lib/Driver/Distro.cpp
35233 views
//===--- Distro.cpp - Linux distribution detection support ------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Driver/Distro.h"9#include "clang/Basic/LLVM.h"10#include "llvm/ADT/SmallVector.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/ADT/StringSwitch.h"13#include "llvm/Support/ErrorOr.h"14#include "llvm/Support/MemoryBuffer.h"15#include "llvm/Support/Threading.h"16#include "llvm/TargetParser/Host.h"17#include "llvm/TargetParser/Triple.h"1819using namespace clang::driver;20using namespace clang;2122static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) {23llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =24VFS.getBufferForFile("/etc/os-release");25if (!File)26File = VFS.getBufferForFile("/usr/lib/os-release");27if (!File)28return Distro::UnknownDistro;2930SmallVector<StringRef, 16> Lines;31File.get()->getBuffer().split(Lines, "\n");32Distro::DistroType Version = Distro::UnknownDistro;3334// Obviously this can be improved a lot.35for (StringRef Line : Lines)36if (Version == Distro::UnknownDistro && Line.starts_with("ID="))37Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(3))38.Case("alpine", Distro::AlpineLinux)39.Case("fedora", Distro::Fedora)40.Case("gentoo", Distro::Gentoo)41.Case("arch", Distro::ArchLinux)42// On SLES, /etc/os-release was introduced in SLES 11.43.Case("sles", Distro::OpenSUSE)44.Case("opensuse", Distro::OpenSUSE)45.Case("exherbo", Distro::Exherbo)46.Default(Distro::UnknownDistro);47return Version;48}4950static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) {51llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =52VFS.getBufferForFile("/etc/lsb-release");53if (!File)54return Distro::UnknownDistro;5556SmallVector<StringRef, 16> Lines;57File.get()->getBuffer().split(Lines, "\n");58Distro::DistroType Version = Distro::UnknownDistro;5960for (StringRef Line : Lines)61if (Version == Distro::UnknownDistro &&62Line.starts_with("DISTRIB_CODENAME="))63Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17))64.Case("hardy", Distro::UbuntuHardy)65.Case("intrepid", Distro::UbuntuIntrepid)66.Case("jaunty", Distro::UbuntuJaunty)67.Case("karmic", Distro::UbuntuKarmic)68.Case("lucid", Distro::UbuntuLucid)69.Case("maverick", Distro::UbuntuMaverick)70.Case("natty", Distro::UbuntuNatty)71.Case("oneiric", Distro::UbuntuOneiric)72.Case("precise", Distro::UbuntuPrecise)73.Case("quantal", Distro::UbuntuQuantal)74.Case("raring", Distro::UbuntuRaring)75.Case("saucy", Distro::UbuntuSaucy)76.Case("trusty", Distro::UbuntuTrusty)77.Case("utopic", Distro::UbuntuUtopic)78.Case("vivid", Distro::UbuntuVivid)79.Case("wily", Distro::UbuntuWily)80.Case("xenial", Distro::UbuntuXenial)81.Case("yakkety", Distro::UbuntuYakkety)82.Case("zesty", Distro::UbuntuZesty)83.Case("artful", Distro::UbuntuArtful)84.Case("bionic", Distro::UbuntuBionic)85.Case("cosmic", Distro::UbuntuCosmic)86.Case("disco", Distro::UbuntuDisco)87.Case("eoan", Distro::UbuntuEoan)88.Case("focal", Distro::UbuntuFocal)89.Case("groovy", Distro::UbuntuGroovy)90.Case("hirsute", Distro::UbuntuHirsute)91.Case("impish", Distro::UbuntuImpish)92.Case("jammy", Distro::UbuntuJammy)93.Case("kinetic", Distro::UbuntuKinetic)94.Case("lunar", Distro::UbuntuLunar)95.Case("mantic", Distro::UbuntuMantic)96.Case("noble", Distro::UbuntuNoble)97.Case("oracular", Distro::UbuntuOracular)98.Default(Distro::UnknownDistro);99return Version;100}101102static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {103Distro::DistroType Version = Distro::UnknownDistro;104105// Newer freedesktop.org's compilant systemd-based systems106// should provide /etc/os-release or /usr/lib/os-release.107Version = DetectOsRelease(VFS);108if (Version != Distro::UnknownDistro)109return Version;110111// Older systems might provide /etc/lsb-release.112Version = DetectLsbRelease(VFS);113if (Version != Distro::UnknownDistro)114return Version;115116// Otherwise try some distro-specific quirks for Red Hat...117llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =118VFS.getBufferForFile("/etc/redhat-release");119120if (File) {121StringRef Data = File.get()->getBuffer();122if (Data.starts_with("Fedora release"))123return Distro::Fedora;124if (Data.starts_with("Red Hat Enterprise Linux") ||125Data.starts_with("CentOS") || Data.starts_with("Scientific Linux")) {126if (Data.contains("release 7"))127return Distro::RHEL7;128else if (Data.contains("release 6"))129return Distro::RHEL6;130else if (Data.contains("release 5"))131return Distro::RHEL5;132}133return Distro::UnknownDistro;134}135136// ...for Debian137File = VFS.getBufferForFile("/etc/debian_version");138if (File) {139StringRef Data = File.get()->getBuffer();140// Contents: < major.minor > or < codename/sid >141int MajorVersion;142if (!Data.split('.').first.getAsInteger(10, MajorVersion)) {143switch (MajorVersion) {144case 5:145return Distro::DebianLenny;146case 6:147return Distro::DebianSqueeze;148case 7:149return Distro::DebianWheezy;150case 8:151return Distro::DebianJessie;152case 9:153return Distro::DebianStretch;154case 10:155return Distro::DebianBuster;156case 11:157return Distro::DebianBullseye;158case 12:159return Distro::DebianBookworm;160case 13:161return Distro::DebianTrixie;162default:163return Distro::UnknownDistro;164}165}166return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first)167.Case("squeeze/sid", Distro::DebianSqueeze)168.Case("wheezy/sid", Distro::DebianWheezy)169.Case("jessie/sid", Distro::DebianJessie)170.Case("stretch/sid", Distro::DebianStretch)171.Case("buster/sid", Distro::DebianBuster)172.Case("bullseye/sid", Distro::DebianBullseye)173.Case("bookworm/sid", Distro::DebianBookworm)174.Case("trixie/sid", Distro::DebianTrixie)175.Default(Distro::UnknownDistro);176}177178// ...for SUSE179File = VFS.getBufferForFile("/etc/SuSE-release");180if (File) {181StringRef Data = File.get()->getBuffer();182SmallVector<StringRef, 8> Lines;183Data.split(Lines, "\n");184for (const StringRef &Line : Lines) {185if (!Line.trim().starts_with("VERSION"))186continue;187std::pair<StringRef, StringRef> SplitLine = Line.split('=');188// Old versions have split VERSION and PATCHLEVEL189// Newer versions use VERSION = x.y190std::pair<StringRef, StringRef> SplitVer =191SplitLine.second.trim().split('.');192int Version;193194// OpenSUSE/SLES 10 and older are not supported and not compatible195// with our rules, so just treat them as Distro::UnknownDistro.196if (!SplitVer.first.getAsInteger(10, Version) && Version > 10)197return Distro::OpenSUSE;198return Distro::UnknownDistro;199}200return Distro::UnknownDistro;201}202203// ...and others.204if (VFS.exists("/etc/gentoo-release"))205return Distro::Gentoo;206207return Distro::UnknownDistro;208}209210static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS,211const llvm::Triple &TargetOrHost) {212// If we don't target Linux, no need to check the distro. This saves a few213// OS calls.214if (!TargetOrHost.isOSLinux())215return Distro::UnknownDistro;216217// True if we're backed by a real file system.218const bool onRealFS = (llvm::vfs::getRealFileSystem() == &VFS);219220// If the host is not running Linux, and we're backed by a real file221// system, no need to check the distro. This is the case where someone222// is cross-compiling from BSD or Windows to Linux, and it would be223// meaningless to try to figure out the "distro" of the non-Linux host.224llvm::Triple HostTriple(llvm::sys::getProcessTriple());225if (!HostTriple.isOSLinux() && onRealFS)226return Distro::UnknownDistro;227228if (onRealFS) {229// If we're backed by a real file system, perform230// the detection only once and save the result.231static Distro::DistroType LinuxDistro = DetectDistro(VFS);232return LinuxDistro;233}234// This is mostly for passing tests which uses llvm::vfs::InMemoryFileSystem,235// which is not "real".236return DetectDistro(VFS);237}238239Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)240: DistroVal(GetDistro(VFS, TargetOrHost)) {}241242243