diff --git a/src/main.cc b/src/main.cc index 4671511a..a112edce 100644 --- a/src/main.cc +++ b/src/main.cc @@ -891,7 +891,7 @@ int main(int argc, char* argv[]) const bool clear_sessions = (bool)parser.get_switch("clear"); if (list_sessions or clear_sessions) { - const StringView username = getpwuid(geteuid())->pw_name; + const String username = get_user_name(geteuid()); const StringView tmp_dir = tmpdir(); for (auto& session : list_files(format("{}/kakoune/{}/", tmp_dir, username))) diff --git a/src/ranges.hh b/src/ranges.hh index fa23f180..599396dc 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -6,6 +6,8 @@ #include #include +#include "constexpr_utils.hh" + namespace Kakoune { @@ -337,6 +339,21 @@ auto gather() }); } +template +auto elements() +{ + return make_view_factory([] (auto&& range) { + using std::begin; using std::end; + auto elem = [it = begin(range), end = end(range), i = 0u](size_t index) mutable { + for (; i < index; ++i, ++it) + if (it == end) throw ExceptionType{i}; + return *it; + }; + // Note that initializer lists elements are guaranteed to be sequenced + return Array, sizeof...(Indexes)>{{elem(Indexes)...}}; + }); +} + } #endif // ranges_hh_INCLUDED diff --git a/src/remote.cc b/src/remote.cc index ebd92f72..8cfbdc5b 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -528,6 +528,23 @@ void RemoteUI::exit(int status) m_socket_watcher.events() |= FdEvents::Write; } +String get_user_name(int uid) +{ + struct invalid_index : runtime_error + { + invalid_index(size_t i) : runtime_error{format("invalid index '{}'", i)} {} + }; + + MappedFile passwd{"/etc/passwd"}; + for (auto entry : (StringView)passwd | split('\n')) + { + auto name_and_id = entry | split(':') | elements(); + if (str_to_int(name_and_id[1]) == uid) + return name_and_id[0].str(); + } + throw runtime_error(format("Cannot find user name for uid '{}'", uid)); +} + static sockaddr_un session_addr(StringView session) { sockaddr_un addr; @@ -539,7 +556,7 @@ static sockaddr_un session_addr(StringView session) format_to(addr.sun_path, "{}/kakoune/{}", tmpdir(), session); else format_to(addr.sun_path, "{}/kakoune/{}/{}", tmpdir(), - getpwuid(geteuid())->pw_name, session); + get_user_name(geteuid()), session); return addr; } @@ -813,9 +830,9 @@ bool Server::rename_session(StringView name) throw runtime_error{"Cannot create sessions with '/' in their name"}; String old_socket_file = format("{}/kakoune/{}/{}", tmpdir(), - getpwuid(geteuid())->pw_name, m_session); + get_user_name(geteuid()), m_session); String new_socket_file = format("{}/kakoune/{}/{}", tmpdir(), - getpwuid(geteuid())->pw_name, name); + get_user_name(geteuid()), name); if (rename(old_socket_file.c_str(), new_socket_file.c_str()) != 0) return false; @@ -829,7 +846,7 @@ void Server::close_session(bool do_unlink) if (do_unlink) { String socket_file = format("{}/kakoune/{}/{}", tmpdir(), - getpwuid(geteuid())->pw_name, m_session); + get_user_name(geteuid()), m_session); unlink(socket_file.c_str()); } m_listener->close_fd(); diff --git a/src/remote.hh b/src/remote.hh index d723713f..ce84cb42 100644 --- a/src/remote.hh +++ b/src/remote.hh @@ -43,6 +43,7 @@ private: }; void send_command(StringView session, StringView command); +String get_user_name(int uid); struct Server : public Singleton {