| 154 | } // anonymous |
| 155 | |
| 156 | ByteBuf format_users(const Engine& eng) { |
| 157 | // Live-task UIDs first — they drive which /etc/passwd copy is "correct". |
| 158 | std::map<u32, std::size_t> proc_count_by_uid; |
| 159 | for (const auto& p : eng.processes()) ++proc_count_by_uid[p.uid]; |
| 160 | |
| 161 | PasswdSource src = select_passwd(eng, proc_count_by_uid); |
| 162 | const auto& by_uid = src.by_uid; |
| 163 | |
| 164 | std::string out; |
| 165 | out.reserve(8 * 1024); |
| 166 | out += fmt::format( |
| 167 | "# /sys/users.txt — UID → name table\n" |
| 168 | "# /etc/passwd source: {}\n" |
| 169 | "# {} entries parsed; {} unique UIDs seen across {} live tasks.\n" |
| 170 | "#\n", |
| 171 | src.origin, by_uid.size(), proc_count_by_uid.size(), eng.processes().size()); |
| 172 | |
| 173 | // Union of UIDs from passwd ∪ live tasks. |
| 174 | std::set<u32> all_uids; |
| 175 | for (auto& [uid, _] : by_uid) all_uids.insert(uid); |
| 176 | for (auto& [uid, _] : proc_count_by_uid) all_uids.insert(uid); |
| 177 | |
| 178 | out += fmt::format("{:>6} {:<16} {:>5} {:>5} {:<24} {}\n", |
| 179 | "UID", "NAME", "PROCS", "GID", "HOME", "SHELL"); |
| 180 | out += std::string(96, '-') + "\n"; |
| 181 | for (u32 uid : all_uids) { |
| 182 | std::size_t nproc = proc_count_by_uid.count(uid) ? proc_count_by_uid.at(uid) : 0; |
| 183 | auto it = by_uid.find(uid); |
| 184 | if (it != by_uid.end()) { |
| 185 | const auto& e = it->second; |
| 186 | out += fmt::format("{:>6} {:<16} {:>5} {:>5} {:<24} {}\n", |
| 187 | uid, e.name.substr(0, 16), nproc, e.gid, |
| 188 | e.home.substr(0, 24), e.shell); |
| 189 | } else { |
| 190 | // UID present in live tasks but not in /etc/passwd (LDAP / |
| 191 | // SSSD / nss-resolve / system uid not in the file / container |
| 192 | // uid_map remap). |
| 193 | out += fmt::format("{:>6} {:<16} {:>5} {:>5} {:<24} {}\n", |
| 194 | uid, "(unresolved)", nproc, "?", |
| 195 | "?", "(not in /etc/passwd)"); |
| 196 | } |
| 197 | } |
| 198 | return ByteBuf(out.begin(), out.end()); |
| 199 | } |
| 200 | |
| 201 | } // namespace lmpfs::linux |
no test coverage detected