SystemServerTakeover.cpp 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /*
  2. * Copyright (c) 2022, sin-ack <sin-ack@protonmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "SystemServerTakeover.h"
  7. #include <LibCore/System.h>
  8. namespace Core {
  9. HashMap<String, int> s_overtaken_sockets {};
  10. bool s_overtaken_sockets_parsed { false };
  11. static void parse_sockets_from_system_server()
  12. {
  13. VERIFY(!s_overtaken_sockets_parsed);
  14. constexpr auto socket_takeover = "SOCKET_TAKEOVER";
  15. char const* sockets = getenv(socket_takeover);
  16. if (!sockets) {
  17. s_overtaken_sockets_parsed = true;
  18. return;
  19. }
  20. for (auto& socket : StringView { sockets, strlen(sockets) }.split_view(' ')) {
  21. auto params = socket.split_view(':');
  22. s_overtaken_sockets.set(params[0].to_string(), strtol(params[1].to_string().characters(), nullptr, 10));
  23. }
  24. s_overtaken_sockets_parsed = true;
  25. // We wouldn't want our children to think we're passing
  26. // them a socket either, so unset the env variable.
  27. unsetenv(socket_takeover);
  28. }
  29. ErrorOr<NonnullOwnPtr<Core::Stream::LocalSocket>> take_over_socket_from_system_server(String const& socket_path)
  30. {
  31. if (!s_overtaken_sockets_parsed)
  32. parse_sockets_from_system_server();
  33. int fd;
  34. if (socket_path.is_null()) {
  35. // We want the first (and only) socket.
  36. VERIFY(s_overtaken_sockets.size() == 1);
  37. fd = s_overtaken_sockets.begin()->value;
  38. } else {
  39. auto it = s_overtaken_sockets.find(socket_path);
  40. if (it == s_overtaken_sockets.end())
  41. return Error::from_string_literal("Non-existent socket requested"sv);
  42. fd = it->value;
  43. }
  44. // Sanity check: it has to be a socket.
  45. auto stat = TRY(Core::System::fstat(fd));
  46. if (!S_ISSOCK(stat.st_mode))
  47. return Error::from_string_literal("The fd we got from SystemServer is not a socket"sv);
  48. auto socket = TRY(Core::Stream::LocalSocket::adopt_fd(fd));
  49. // It had to be !CLOEXEC for obvious reasons, but we
  50. // don't need it to be !CLOEXEC anymore, so set the
  51. // CLOEXEC flag now.
  52. TRY(socket->set_close_on_exec(true));
  53. return socket;
  54. }
  55. }