busybox_info.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/install/busybox_info.h"
  5. #include <iterator>
  6. #include "common/exe_path.h"
  7. #include "llvm/ADT/StringRef.h"
  8. namespace Carbon {
  9. // The mode is set to the initial filename used for `argv[0]`.
  10. static auto GetMode(const std::filesystem::path& argv0)
  11. -> std::optional<std::string> {
  12. std::string filename = argv0.filename();
  13. if (filename != "carbon" && filename != "carbon-busybox") {
  14. return filename;
  15. }
  16. return std::nullopt;
  17. }
  18. auto GetBusyboxInfo(const char* argv0) -> ErrorOr<BusyboxInfo> {
  19. // Need storage due to `unsetenv` affecting `getenv` lifetime; using `path`
  20. // for `GetMode`.
  21. std::filesystem::path argv0_path = argv0;
  22. // Check for an override of `argv[0]` from the environment and apply it.
  23. if (const char* argv0_override = getenv(Argv0OverrideEnv)) {
  24. argv0_path = argv0_override;
  25. unsetenv(Argv0OverrideEnv);
  26. }
  27. BusyboxInfo info = {.bin_path = FindExecutablePath(argv0_path.c_str()),
  28. .mode = GetMode(argv0_path)};
  29. // Now search through any symlinks to locate the installed busybox binary.
  30. while (true) {
  31. if (info.bin_path.filename() == "carbon-busybox") {
  32. // Check for bazel structure. For example, this makes work:
  33. // /bin/sh -c "exec -a carbon ./bazel-bin/toolchain/carbon"
  34. // /bin/sh -c "exec -a llvm-symbolizer ./bazel-bin/toolchain/carbon"
  35. //
  36. // This will never occur in a "bin" subdirectory, so doesn't need to be
  37. // handled in the other return path.
  38. std::string prefix_root = info.bin_path.parent_path().string() +
  39. "/prefix_root/lib/carbon/carbon-busybox";
  40. if (std::filesystem::exists(prefix_root)) {
  41. info.bin_path = prefix_root;
  42. }
  43. return info;
  44. }
  45. // If we've not already reached the busybox, look for it relative to the
  46. // current binary path. This can help more immediately locate an
  47. // installation tree, and avoids walking through a final layer of symlinks
  48. // which may point to content-addressed storage or other parts of a build
  49. // output tree.
  50. //
  51. // We break this into two cases we need to handle:
  52. // - Carbon's CLI will be: `<prefix>/bin/carbon`
  53. // - Other tools will be: `<prefix>/lib/carbon/<group>/bin/<tool>`
  54. //
  55. // We also check that the current path is within a `bin` directory to
  56. // provide best-effort checking for accidentally walking up from symlinks
  57. // that aren't within an installation-shaped tree.
  58. auto parent_path = info.bin_path.parent_path();
  59. // Strip any `.` path components at the end to simplify processing.
  60. while (parent_path.filename() == ".") {
  61. parent_path = parent_path.parent_path();
  62. }
  63. if (parent_path.filename() == "bin") {
  64. auto lib_path = info.bin_path.filename() == "carbon"
  65. ? parent_path / ".." / "lib" / "carbon"
  66. : parent_path / ".." / "..";
  67. auto busybox_path = lib_path / "carbon-busybox";
  68. std::error_code ec;
  69. if (std::filesystem::exists(busybox_path, ec)) {
  70. info.bin_path = busybox_path;
  71. return info;
  72. }
  73. }
  74. // Try to walk through another layer of symlinks and see if we can find the
  75. // installation there or are linked directly to the busybox.
  76. std::error_code ec;
  77. auto symlink_target = std::filesystem::read_symlink(info.bin_path, ec);
  78. if (ec) {
  79. return ErrorBuilder()
  80. << "expected carbon-busybox symlink at `" << info.bin_path << "`";
  81. }
  82. // Do a path join, to handle relative symlinks.
  83. info.bin_path = parent_path / symlink_target;
  84. }
  85. }
  86. } // namespace Carbon