Environment.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021-2022, Kenneth Myhra <kennethmyhra@serenityos.org>
  4. * Copyright (c) 2021-2024, Sam Atkins <atkinssj@serenityos.org>
  5. * Copyright (c) 2022, Matthias Zimmerman <matthias291999@gmail.com>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include "Environment.h"
  10. #include <AK/ByteString.h>
  11. #if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
  12. # include <crt_externs.h>
  13. #else
  14. extern "C" char** environ;
  15. #endif
  16. namespace Core::Environment {
  17. char** raw_environ()
  18. {
  19. #if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
  20. return *_NSGetEnviron();
  21. #else
  22. return environ;
  23. #endif
  24. }
  25. Entry Entry::from_chars(char const* input)
  26. {
  27. return Entry::from_string({ input, strlen(input) });
  28. }
  29. Entry Entry::from_string(StringView input)
  30. {
  31. auto split_index = input.find('=');
  32. if (!split_index.has_value()) {
  33. return Entry {
  34. .full_entry = input,
  35. .name = input,
  36. .value = ""sv,
  37. };
  38. }
  39. return Entry {
  40. .full_entry = input,
  41. .name = input.substring_view(0, *split_index),
  42. .value = input.substring_view(*split_index + 1),
  43. };
  44. }
  45. EntryIterator EntryIterator::begin()
  46. {
  47. return EntryIterator(0);
  48. }
  49. EntryIterator EntryIterator::end()
  50. {
  51. auto environment = raw_environ();
  52. size_t env_count = 0;
  53. for (size_t i = 0; environment[i]; ++i)
  54. ++env_count;
  55. return EntryIterator(env_count);
  56. }
  57. EntryIterator entries()
  58. {
  59. return EntryIterator::begin();
  60. }
  61. size_t size()
  62. {
  63. auto environment = raw_environ();
  64. size_t environ_size = 0;
  65. while (environment[environ_size])
  66. ++environ_size;
  67. return environ_size;
  68. }
  69. bool has(StringView name)
  70. {
  71. return get(name).has_value();
  72. }
  73. Optional<StringView> get(StringView name, [[maybe_unused]] SecureOnly secure)
  74. {
  75. StringBuilder builder;
  76. builder.append(name);
  77. builder.append('\0');
  78. // Note the explicit null terminators above.
  79. // FreeBSD < 14, Android, and generic BSDs do not support secure_getenv.
  80. #if (defined(__FreeBSD__) && __FreeBSD__ >= 14) || (!defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID))
  81. char* result;
  82. if (secure == SecureOnly::Yes) {
  83. result = ::secure_getenv(builder.string_view().characters_without_null_termination());
  84. } else {
  85. result = ::getenv(builder.string_view().characters_without_null_termination());
  86. }
  87. #else
  88. char* result = ::getenv(builder.string_view().characters_without_null_termination());
  89. #endif
  90. if (result)
  91. return StringView { result, strlen(result) };
  92. return {};
  93. }
  94. ErrorOr<void> set(StringView name, StringView value, Overwrite overwrite)
  95. {
  96. auto builder = TRY(StringBuilder::create());
  97. TRY(builder.try_append(name));
  98. TRY(builder.try_append('\0'));
  99. TRY(builder.try_append(value));
  100. TRY(builder.try_append('\0'));
  101. // Note the explicit null terminators above.
  102. auto c_name = builder.string_view().characters_without_null_termination();
  103. auto c_value = c_name + name.length() + 1;
  104. auto rc = ::setenv(c_name, c_value, overwrite == Overwrite::Yes ? 1 : 0);
  105. if (rc < 0)
  106. return Error::from_errno(errno);
  107. return {};
  108. }
  109. ErrorOr<void> unset(StringView name)
  110. {
  111. auto builder = TRY(StringBuilder::create());
  112. TRY(builder.try_append(name));
  113. TRY(builder.try_append('\0'));
  114. // Note the explicit null terminator above.
  115. auto rc = ::unsetenv(builder.string_view().characters_without_null_termination());
  116. if (rc < 0)
  117. return Error::from_errno(errno);
  118. return {};
  119. }
  120. ErrorOr<void> put(StringView env)
  121. {
  122. #if defined(AK_OS_SERENITY)
  123. auto rc = ::serenity_putenv(env.characters_without_null_termination(), env.length());
  124. #else
  125. // Leak somewhat unavoidable here due to the putenv API.
  126. auto leaked_new_env = strndup(env.characters_without_null_termination(), env.length());
  127. auto rc = ::putenv(leaked_new_env);
  128. #endif
  129. if (rc < 0)
  130. return Error::from_errno(errno);
  131. return {};
  132. }
  133. ErrorOr<void> clear()
  134. {
  135. #if (defined(__FreeBSD__) && __FreeBSD__ < 14)
  136. environ = nullptr;
  137. #elif defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_FREEBSD)
  138. auto environment = raw_environ();
  139. for (size_t environ_size = 0; environment[environ_size]; ++environ_size) {
  140. environment[environ_size] = NULL;
  141. }
  142. #else
  143. auto rc = ::clearenv();
  144. if (rc < 0)
  145. return Error::from_errno(errno);
  146. #endif
  147. return {};
  148. }
  149. }