turbonss-analyze: most memberships

This commit is contained in:
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; return self.inner.gid;
} }
pub fn membersOffset(self: *const PackedGroup) u64 { pub inline fn membersOffset(self: *const PackedGroup) u64 {
return self.members_offset; return self.members_offset;
} }
pub fn name(self: *const PackedGroup) []const u8 { pub inline fn name(self: *const PackedGroup) []const u8 {
return self.groupdata; return self.groupdata;
} }

View File

@ -12,9 +12,11 @@ const Allocator = std.mem.Allocator;
const BoundedArray = std.BoundedArray; const BoundedArray = std.BoundedArray;
const flags = @import("flags.zig"); const flags = @import("flags.zig");
const compress = @import("compress.zig");
const DB = @import("DB.zig"); const DB = @import("DB.zig");
const File = @import("File.zig"); const File = @import("File.zig");
const PackedUser = @import("PackedUser.zig"); const PackedUser = @import("PackedUser.zig");
const PackedGroup = @import("PackedGroup.zig");
const Header = @import("header.zig").Header; const Header = @import("header.zig").Header;
const section_length_bits = @import("header.zig").section_length_bits; const section_length_bits = @import("header.zig").section_length_bits;
@ -61,12 +63,12 @@ fn execute(
const myflags = flags.parse(argv, &[_]flags.Flag{ const myflags = flags.parse(argv, &[_]flags.Flag{
.{ .name = "-h", .kind = .boolean }, .{ .name = "-h", .kind = .boolean },
}) catch { }) catch {
stderr.writeAll(usage) catch {}; stderr.writeAll(usage) catch return 3;
return 1; return 1;
}; };
if (myflags.boolFlag("-h")) { if (myflags.boolFlag("-h")) {
stdout.writeAll(usage) catch return 1; stdout.writeAll(usage) catch return 3;
return 0; return 0;
} }
@ -74,8 +76,8 @@ fn execute(
0 => "/etc/turbonss/db.turbo", 0 => "/etc/turbonss/db.turbo",
1 => mem.span(myflags.args[0]), 1 => mem.span(myflags.args[0]),
else => { else => {
stderr.print("ERROR: too many arguments\n", .{}) catch {}; stderr.print("ERROR: too many arguments\n", .{}) catch return 3;
stderr.writeAll(usage) catch {}; stderr.writeAll(usage) catch return 3;
return 1; return 1;
}, },
}; };
@ -133,14 +135,54 @@ fn execute(
\\Users: {[users]d} \\Users: {[users]d}
\\Groups: {[groups]d} \\Groups: {[groups]d}
\\Shells: {[shells]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 lengths = DB.fieldLengths(db.header);
var offsets = DB.fieldOffsets(lengths); var offsets = DB.fieldOffsets(lengths);
stdout.writeAll(
\\Sections:
\\ Name Begin End Size bytes
\\
) catch return 3;
inline for (meta.fields(DB.DBNumbers)) |field| { inline for (meta.fields(DB.DBNumbers)) |field| {
const length = @field(lengths, field.name); const length = @field(lengths, field.name);
@ -151,7 +193,7 @@ fn execute(
start << section_length_bits, start << section_length_bits,
end << section_length_bits, end << section_length_bits,
splitInt(length << section_length_bits).constSlice(), splitInt(length << section_length_bits).constSlice(),
}) catch {}; }) catch return 3;
} }
return 0; return 0;