turbonss-analyze: most memberships
This commit is contained in:
parent
8ceacc04b8
commit
bd13e6a322
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user