Distro.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. #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. using namespace clang::driver;
  16. using namespace clang;
  17. static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
  18. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
  19. VFS.getBufferForFile("/etc/lsb-release");
  20. if (File) {
  21. StringRef Data = File.get()->getBuffer();
  22. SmallVector<StringRef, 16> Lines;
  23. Data.split(Lines, "\n");
  24. Distro::DistroType Version = Distro::UnknownDistro;
  25. for (StringRef Line : Lines)
  26. if (Version == Distro::UnknownDistro && Line.startswith("DISTRIB_CODENAME="))
  27. Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17))
  28. .Case("hardy", Distro::UbuntuHardy)
  29. .Case("intrepid", Distro::UbuntuIntrepid)
  30. .Case("jaunty", Distro::UbuntuJaunty)
  31. .Case("karmic", Distro::UbuntuKarmic)
  32. .Case("lucid", Distro::UbuntuLucid)
  33. .Case("maverick", Distro::UbuntuMaverick)
  34. .Case("natty", Distro::UbuntuNatty)
  35. .Case("oneiric", Distro::UbuntuOneiric)
  36. .Case("precise", Distro::UbuntuPrecise)
  37. .Case("quantal", Distro::UbuntuQuantal)
  38. .Case("raring", Distro::UbuntuRaring)
  39. .Case("saucy", Distro::UbuntuSaucy)
  40. .Case("trusty", Distro::UbuntuTrusty)
  41. .Case("utopic", Distro::UbuntuUtopic)
  42. .Case("vivid", Distro::UbuntuVivid)
  43. .Case("wily", Distro::UbuntuWily)
  44. .Case("xenial", Distro::UbuntuXenial)
  45. .Case("yakkety", Distro::UbuntuYakkety)
  46. .Case("zesty", Distro::UbuntuZesty)
  47. .Case("artful", Distro::UbuntuArtful)
  48. .Case("bionic", Distro::UbuntuBionic)
  49. .Case("cosmic", Distro::UbuntuCosmic)
  50. .Case("disco", Distro::UbuntuDisco)
  51. .Case("eoan", Distro::UbuntuEoan)
  52. .Default(Distro::UnknownDistro);
  53. if (Version != Distro::UnknownDistro)
  54. return Version;
  55. }
  56. File = VFS.getBufferForFile("/etc/redhat-release");
  57. if (File) {
  58. StringRef Data = File.get()->getBuffer();
  59. if (Data.startswith("Fedora release"))
  60. return Distro::Fedora;
  61. if (Data.startswith("Red Hat Enterprise Linux") ||
  62. Data.startswith("CentOS") ||
  63. Data.startswith("Scientific Linux")) {
  64. if (Data.find("release 7") != StringRef::npos)
  65. return Distro::RHEL7;
  66. else if (Data.find("release 6") != StringRef::npos)
  67. return Distro::RHEL6;
  68. else if (Data.find("release 5") != StringRef::npos)
  69. return Distro::RHEL5;
  70. }
  71. return Distro::UnknownDistro;
  72. }
  73. File = VFS.getBufferForFile("/etc/debian_version");
  74. if (File) {
  75. StringRef Data = File.get()->getBuffer();
  76. // Contents: < major.minor > or < codename/sid >
  77. int MajorVersion;
  78. if (!Data.split('.').first.getAsInteger(10, MajorVersion)) {
  79. switch (MajorVersion) {
  80. case 5:
  81. return Distro::DebianLenny;
  82. case 6:
  83. return Distro::DebianSqueeze;
  84. case 7:
  85. return Distro::DebianWheezy;
  86. case 8:
  87. return Distro::DebianJessie;
  88. case 9:
  89. return Distro::DebianStretch;
  90. case 10:
  91. return Distro::DebianBuster;
  92. case 11:
  93. return Distro::DebianBullseye;
  94. default:
  95. return Distro::UnknownDistro;
  96. }
  97. }
  98. return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first)
  99. .Case("squeeze/sid", Distro::DebianSqueeze)
  100. .Case("wheezy/sid", Distro::DebianWheezy)
  101. .Case("jessie/sid", Distro::DebianJessie)
  102. .Case("stretch/sid", Distro::DebianStretch)
  103. .Case("buster/sid", Distro::DebianBuster)
  104. .Case("bullseye/sid", Distro::DebianBullseye)
  105. .Default(Distro::UnknownDistro);
  106. }
  107. File = VFS.getBufferForFile("/etc/SuSE-release");
  108. if (File) {
  109. StringRef Data = File.get()->getBuffer();
  110. SmallVector<StringRef, 8> Lines;
  111. Data.split(Lines, "\n");
  112. for (const StringRef& Line : Lines) {
  113. if (!Line.trim().startswith("VERSION"))
  114. continue;
  115. std::pair<StringRef, StringRef> SplitLine = Line.split('=');
  116. // Old versions have split VERSION and PATCHLEVEL
  117. // Newer versions use VERSION = x.y
  118. std::pair<StringRef, StringRef> SplitVer = SplitLine.second.trim().split('.');
  119. int Version;
  120. // OpenSUSE/SLES 10 and older are not supported and not compatible
  121. // with our rules, so just treat them as Distro::UnknownDistro.
  122. if (!SplitVer.first.getAsInteger(10, Version) && Version > 10)
  123. return Distro::OpenSUSE;
  124. return Distro::UnknownDistro;
  125. }
  126. return Distro::UnknownDistro;
  127. }
  128. if (VFS.exists("/etc/exherbo-release"))
  129. return Distro::Exherbo;
  130. if (VFS.exists("/etc/alpine-release"))
  131. return Distro::AlpineLinux;
  132. if (VFS.exists("/etc/arch-release"))
  133. return Distro::ArchLinux;
  134. if (VFS.exists("/etc/gentoo-release"))
  135. return Distro::Gentoo;
  136. return Distro::UnknownDistro;
  137. }
  138. Distro::Distro(llvm::vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {}