Serenity Operating System
at master 78 lines 2.3 kB view raw
1/* 2 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Assertions.h> 8#include <AK/ByteBuffer.h> 9#include <AK/JsonObject.h> 10#include <AK/JsonValue.h> 11#include <LibCore/ArgsParser.h> 12#include <LibCore/DateTime.h> 13#include <LibCore/File.h> 14#include <LibCore/System.h> 15#include <LibMain/Main.h> 16#include <unistd.h> 17 18ErrorOr<int> serenity_main(Main::Arguments arguments) 19{ 20 TRY(Core::System::pledge("stdio wpath cpath")); 21 TRY(Core::System::unveil("/var/run/utmp", "rwc")); 22 TRY(Core::System::unveil(nullptr, nullptr)); 23 24 pid_t pid = 0; 25 bool flag_create = false; 26 bool flag_delete = false; 27 StringView tty_name; 28 StringView from; 29 30 Core::ArgsParser args_parser; 31 args_parser.add_option(flag_create, "Create entry", "create", 'c'); 32 args_parser.add_option(flag_delete, "Delete entry", "delete", 'd'); 33 args_parser.add_option(pid, "PID", "PID", 'p', "PID"); 34 args_parser.add_option(from, "From", "from", 'f', "From"); 35 args_parser.add_positional_argument(tty_name, "TTY name", "tty"); 36 args_parser.parse(arguments); 37 38 if (flag_create && flag_delete) { 39 warnln("-c and -d are mutually exclusive"); 40 return 1; 41 } 42 43 dbgln("Updating utmp from UID={} GID={} EGID={} PID={}", getuid(), getgid(), getegid(), pid); 44 45 auto file = TRY(Core::File::open("/var/run/utmp"sv, Core::File::OpenMode::ReadWrite)); 46 47 auto file_contents = TRY(file->read_until_eof()); 48 auto previous_json = TRY(JsonValue::from_string(file_contents)); 49 50 JsonObject json; 51 52 if (!file_contents.is_empty()) { 53 if (!previous_json.is_object()) { 54 dbgln("Error: Could not parse JSON"); 55 } else { 56 json = previous_json.as_object(); 57 } 58 } 59 60 if (flag_create) { 61 JsonObject entry; 62 entry.set("pid", pid); 63 entry.set("uid", getuid()); 64 entry.set("from", from); 65 entry.set("login_at", time(nullptr)); 66 json.set(tty_name, move(entry)); 67 } else { 68 VERIFY(flag_delete); 69 dbgln("Removing {} from utmp", tty_name); 70 json.remove(tty_name); 71 } 72 73 TRY(file->seek(0, SeekMode::SetPosition)); 74 TRY(file->truncate(0)); 75 TRY(file->write_until_depleted(json.to_deprecated_string().bytes())); 76 77 return 0; 78}