Serenity Operating System
at master 141 lines 4.1 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/StringUtils.h> 8#include <LibCore/Account.h> 9#include <LibCore/ArgsParser.h> 10#include <LibCore/System.h> 11#include <LibMain/Main.h> 12#include <alloca.h> 13#include <grp.h> 14#include <pwd.h> 15#include <stdio.h> 16#include <unistd.h> 17 18static int print_id_objects(Core::Account const&); 19 20static bool flag_print_uid = false; 21static bool flag_print_gid = false; 22static bool flag_print_name = false; 23static bool flag_print_gid_all = false; 24static DeprecatedString user_str; 25 26ErrorOr<int> serenity_main(Main::Arguments arguments) 27{ 28 TRY(Core::System::unveil("/etc/passwd", "r")); 29 TRY(Core::System::unveil("/etc/group", "r")); 30 TRY(Core::System::unveil(nullptr, nullptr)); 31 TRY(Core::System::pledge("stdio rpath")); 32 33 Core::ArgsParser args_parser; 34 args_parser.add_option(flag_print_uid, "Print UID", nullptr, 'u'); 35 args_parser.add_option(flag_print_gid, "Print GID", nullptr, 'g'); 36 args_parser.add_option(flag_print_gid_all, "Print all GIDs", nullptr, 'G'); 37 args_parser.add_option(flag_print_name, "Print name", nullptr, 'n'); 38 args_parser.add_positional_argument(user_str, "User name/UID to query", "USER", Core::ArgsParser::Required::No); 39 args_parser.parse(arguments); 40 41 if (flag_print_name && !(flag_print_uid || flag_print_gid || flag_print_gid_all)) { 42 warnln("cannot print only names or real IDs in default format"); 43 return 1; 44 } 45 46 if (flag_print_uid + flag_print_gid + flag_print_gid_all > 1) { 47 warnln("cannot print \"only\" of more than one choice"); 48 return 1; 49 } 50 51 Optional<Core::Account> account; 52 if (!user_str.is_empty()) { 53 if (auto user_id = user_str.to_uint(); user_id.has_value()) 54 account = TRY(Core::Account::from_uid(user_id.value(), Core::Account::Read::PasswdOnly)); 55 else 56 account = TRY(Core::Account::from_name(user_str, Core::Account::Read::PasswdOnly)); 57 } else { 58 account = TRY(Core::Account::self(Core::Account::Read::PasswdOnly)); 59 } 60 61 return print_id_objects(account.value()); 62} 63 64static bool print_uid_object(Core::Account const& account) 65{ 66 if (flag_print_name) 67 out("{}", account.username()); 68 else 69 out("{}", account.uid()); 70 71 return true; 72} 73 74static bool print_gid_object(Core::Account const& account) 75{ 76 if (flag_print_name) { 77 struct group* gr = getgrgid(account.gid()); 78 out("{}", gr ? gr->gr_name : "n/a"); 79 } else 80 out("{}", account.gid()); 81 82 return true; 83} 84 85static bool print_gid_list(Core::Account const& account) 86{ 87 auto& extra_gids = account.extra_gids(); 88 auto extra_gid_count = extra_gids.size(); 89 for (size_t g = 0; g < extra_gid_count; ++g) { 90 auto gid = extra_gids[g]; 91 auto* gr = getgrgid(gid); 92 if (flag_print_name && gr) 93 out("{}", gr->gr_name); 94 else 95 out("{}", gid); 96 if (g != extra_gid_count - 1) 97 out(" "); 98 } 99 100 return true; 101} 102 103static bool print_full_id_list(Core::Account const& account) 104{ 105 auto uid = account.uid(); 106 auto gid = account.gid(); 107 struct passwd* pw = getpwuid(uid); 108 struct group* gr = getgrgid(gid); 109 110 out("uid={}({}) gid={}({})", uid, pw ? pw->pw_name : "n/a", gid, gr ? gr->gr_name : "n/a"); 111 112 for (auto extra_gid : account.extra_gids()) { 113 auto* gr = getgrgid(extra_gid); 114 if (gr) 115 out(" {}({})", extra_gid, gr->gr_name); 116 else 117 out(" {}", extra_gid); 118 } 119 120 return true; 121} 122 123static int print_id_objects(Core::Account const& account) 124{ 125 if (flag_print_uid) { 126 if (!print_uid_object(account)) 127 return 1; 128 } else if (flag_print_gid) { 129 if (!print_gid_object(account)) 130 return 1; 131 } else if (flag_print_gid_all) { 132 if (!print_gid_list(account)) 133 return 1; 134 } else { 135 if (!print_full_id_list(account)) 136 return 1; 137 } 138 139 outln(); 140 return 0; 141}