1
Fork 0

turbonss-analyze: most memberships

main
Motiejus Jakštys 2022-07-15 09:01:51 +03:00
parent 8ceacc04b8
commit bd13e6a322
2 changed files with 53 additions and 11 deletions

View File

@ -86,15 +86,15 @@ pub fn iterator(section: []const u8, total: u32) Iterator {
};
}
pub fn gid(self: *const PackedGroup) u32 {
pub inline fn gid(self: *const PackedGroup) u32 {
return self.inner.gid;
}
pub fn membersOffset(self: *const PackedGroup) u64 {
pub inline fn membersOffset(self: *const PackedGroup) u64 {
return self.members_offset;
}
pub fn name(self: *const PackedGroup) []const u8 {
pub inline fn name(self: *const PackedGroup) []const u8 {
return self.groupdata;
}

View File

@ -12,9 +12,11 @@ const Allocator = std.mem.Allocator;
const BoundedArray = std.BoundedArray;
const flags = @import("flags.zig");
const compress = @import("compress.zig");
const DB = @import("DB.zig");
const File = @import("File.zig");
const PackedUser = @import("PackedUser.zig");
const PackedGroup = @import("PackedGroup.zig");
const Header = @import("header.zig").Header;
const section_length_bits = @import("header.zig").section_length_bits;
@ -61,12 +63,12 @@ fn execute(
const myflags = flags.parse(argv, &[_]flags.Flag{
.{ .name = "-h", .kind = .boolean },
}) catch {
stderr.writeAll(usage) catch {};
stderr.writeAll(usage) catch return 3;
return 1;
};
if (myflags.boolFlag("-h")) {
stdout.writeAll(usage) catch return 1;
stdout.writeAll(usage) catch return 3;
return 0;
}
@ -74,8 +76,8 @@ fn execute(
0 => "/etc/turbonss/db.turbo",
1 => mem.span(myflags.args[0]),
else => {
stderr.print("ERROR: too many arguments\n", .{}) catch {};
stderr.writeAll(usage) catch {};
stderr.print("ERROR: too many arguments\n", .{}) catch return 3;
stderr.writeAll(usage) catch return 3;
return 1;
},
};
@ -133,14 +135,54 @@ fn execute(
\\Users: {[users]d}
\\Groups: {[groups]d}
\\Shells: {[shells]d}
\\Sections:
\\ Name Begin End Size bytes
\\
;
stdout.print(template, info) catch {};
stdout.print(template, info) catch return 3;
// Popularity contest:
// - user with most groups
// - TODO: group with most users. Not trivial, because
// group memberships do not include users whose primary
// gid is the target one.
if (db.header.num_users > 0) {
const Name = BoundedArray(u8, 32);
const Popular = struct {
name: Name = Name.init(0) catch unreachable,
score: u64 = 0,
};
var popUser = Popular{};
var it = PackedUser.iterator(
db.users,
db.header.num_users,
db.shellReader(),
);
while (it.next()) |packed_user| {
const offset = packed_user.additional_gids_offset;
const additional_gids = db.additional_gids[offset..];
const vit = compress.varintSliceIteratorMust(additional_gids);
// the primary gid of the user is never in "additional gids"
const ngroups = vit.remaining + 1;
if (ngroups > popUser.score) {
const name = packed_user.name();
popUser.name = Name.fromSlice(name) catch unreachable;
popUser.score = ngroups;
}
}
stdout.print("Most memberships: {s} ({d})\n", .{
popUser.name.constSlice(),
popUser.score,
}) catch return 3;
}
var lengths = DB.fieldLengths(db.header);
var offsets = DB.fieldOffsets(lengths);
stdout.writeAll(
\\Sections:
\\ Name Begin End Size bytes
\\
) catch return 3;
inline for (meta.fields(DB.DBNumbers)) |field| {
const length = @field(lengths, field.name);
@ -151,7 +193,7 @@ fn execute(
start << section_length_bits,
end << section_length_bits,
splitInt(length << section_length_bits).constSlice(),
}) catch {};
}) catch return 3;
}
return 0;