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